reactjs - Redux:使共享组件触发唯一的redux路径取决于父组件

标签 reactjs redux

这是我的场景:我有一个包含问题列表的提要。在每个问题中,我都有一个投票按钮,用于对此问题进行投票。

所以我将设计一个在其他问题组件之间共享的赞成按钮组件。当点击此按钮时,按钮将向服务器触发一个事件。有时方法签名例如:

func upvote(questionOwnerId, upvoteUserId) { ... }

投票后,upvote 将分别为 redux 句柄和更新状态调度一个事件。因此,投票按钮将始终显示最新状态。 (有多少用户对该问题投了赞成票)。

这是我的问题:我不知道如何制作共享组件(upvote组件),在调用服务器方法后触发redux树上的唯一 redux路径.

我有一个解决方案:Upvote 组件将接收以下参数:

  • 点赞总数。
  • 问题的用户 ID。
  • redux 路径。

然后upvote函数和Reducer将分别使用redux路径来更新redux树上的状态。这种方法效果好吗,并且项目看起来干净吗?或者有什么“真正”的方法可以解决我的问题吗?

@Edit: Redux 路径例如:索引 0 处的问题组件的 feeds.item.questionList.question[0]feeds.item.questionList.question[1] 用于 1 个索引处的问题组件...因此Reducer 可以了解如何更新 redux 树。

最佳答案

这样的共享组件只需接收正确的 props 即可完成。并传递通用 onClick事件。

例如,假设我们创建名为 <Question /> 的组件它将是 Prop :

  1. votes - 显示当前投票数。
  2. onUpvote - 作为投票按钮的点击事件。
  3. onDownvote - 作为否决按钮的点击事件。
  4. id - 它需要 id为了将其传递给 parent 功能。
  5. question - 要显示的问题的值。

现在,您的父组件将采用 questions 的列表来自redux-store并将.map并会针对每个问题返回 <Question />具有相应 props 的组件( idvotesquestion )。
至于onUpVoteonDownVote您将传递在父级中创建的函数。这些函数将调度操作,并由您的 reducer 处理,该 reducer 将返回新状态,这将触发重新渲染并显示新数据。

我创建了一个简单的示例,请注意,我不能使用 redux在这里我管理了 App 内的状态组件,但我在评论中提到您可以在其中分派(dispatch)操作以及 reducer 内部应包含哪些逻辑。

const questionsList = [
  {
    id: 1,
    votes: 2,
    question: "whats up"
  },
  {
    id: 2,
    votes: -1,
    question: "whats the time"
  },
  {
    id: 3,
    votes: 0,
    question: "where are you"
  },
  {
    id: 4,
    votes: 7,
    question: "who are you"
  }
];

class Question extends React.Component {
  constructor(props) {
    super(props);

    this.onUpvote = this.onUpvote.bind(this);
    this.onDownvote = this.onDownvote.bind(this);
  }

  onUpvote() {
    const { id, onUpvote } = this.props;
    onUpvote(id);
  }

  onDownvote() {
    const { id, onDownvote } = this.props;
    onDownvote(id);
  }

  render() {
    const { votes, question } = this.props;
    const voteClassName = `votes ${votes < 0 ? 'low' : 'high'}`;
    return (
      <div className="question-wrapper">
        <div className="buttons-wrapper">
          <button className="button" onClick={this.onUpvote}>+</button>
          <div className={voteClassName}>{votes}</div>
          <button className="button" onClick={this.onDownvote}>-</button>
        </div>
        <div className="question">{question}</div>
      </div>
    );
  }
}

class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      questions: questionsList
    };

    this.onUpvote = this.onUpvote.bind(this);
    this.onDownvote = this.onDownvote.bind(this);
  }

  onUpvote(id) {
    const { questions } = this.state;
    // you can dispatch an action here
    // and instead of doing this logic in here you can do it in your reducer
    const nextState = questions.map(question => {
      if (question.id != id) {
        return question;
      }

      return {
        ...question,
        votes: question.votes + 1
      };
    });

    this.setState({ questions: nextState });
  }

  onDownvote(id) {
    const { questions } = this.state;
    // you can dispatch an action here
    // and instead of doing this logic in here you can do it in your reducer
    const nextState = questions.map(question => {
      if (question.id != id) {
        return question;
      }

      return {
        ...question,
        votes: question.votes - 1
      };
    });

    this.setState({ questions: nextState });
  }


  render() {
    const { questions } = this.state; // get the questions via props (redux store)
    return (
      <div>
        {questions.map(q => (
          <Question
            id={q.id}
            question={q.question}
            votes={q.votes}
            onUpvote={this.onUpvote}
            onDownvote={this.onDownvote}
          />
        ))}
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));
.question-wrapper{
  display: flex;
  flex-direction: row;
  width: 150px;
  box-shadow: 0 0 2px 1px #333;
  margin: 10px 0;
  padding: 5px 20px;
}

.buttons-wrapper{
  display:flex;
  flex-direction: column;
}

.button{
  margin: 10px 0;
  cursor: pointer;
}

.question{
  align-self: center;
  margin: 0 20px;
  font-size: 22px;
}

.high{
  color: #3cba54;
}

.low{
  color: #db3236;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

关于reactjs - Redux:使共享组件触发唯一的redux路径取决于父组件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46285879/

相关文章:

reactjs - 警告 : Accessing PropTypes via the main React package is deprecated. 请改用 npm 中的 prop-types 包

typescript - 如何使用 typescript 在react-router Route Handler上编写自己的属性

css - 如何改变 Ant 设计 Tooltip 的宽度

android - 在 ubuntu 16.04 上设置 react-native 时出错

reactjs - 将 brotli 与 AWS Cloudfront + S3 结合使用

javascript - 在根组件中通过 React Context 传递 Redux 存储是正确的方法吗?

javascript - redux中间件函数级联应该这么复杂吗?

javascript - axios 库中的超时功能不起作用

reactjs - React hooks : are they useful for shared state management, 例如终极版?

javascript - 使用 Normalizr 后排序