【问题标题】:Do I need Redux to display ItemList on the left and ItemContent on the right?我需要 Redux 在左侧显示 ItemList 并在右侧显示 ItemContent 吗?
【发布时间】:2018-03-31 00:18:52
【问题描述】:

我真的需要 Redux 来管理应用程序状态来实现这一点吗?如果不是 - 我如何管理/实现 <ItemList /><ItemContent >/ 组件的路由和状态?

  • 我应该创建<ItemsListAndContent /> 组件并嵌套其他组件吗? 组件在?
  • 也许这就是 HOC 的情况?

什么是最好的 方法?

为了阐明应用程序结构,这里有一张图片:

当前案例和代码:

我的应用状态从<App /> 传递到<ExpenseList />

class ExpenseList extends Component {

  const details = passExpenseProps(expense){
    return (
      <div>
        <ExpenseDetails expenseProps={expense} />
      </div>

    )
  }

  render () {
    const {expenses} = this.props;
    const list = expenses.expenseList.map(expense =>
        <Segment clearing key={expense.uid} >
          <a href="" onClick={() => {this.passExpenseProps(expense)}}>
            {expense.createdAt}
          </a>
          <Button floated='right'>
            Preview / Print
          </Button>
        </Segment>
    )

    return (
        <div>

          <Grid celled='internally'>
            <Grid.Row>
              <Grid.Column width={5}>
                <div>
                  <h1>Your Expense List:</h1>
                  <Button onClick={this.props.loadSamples}>Load Sample Expenses</Button>
                  <Segment.Group raised>

                    {list}

                  </Segment.Group>
                </div>

              </Grid.Column>
              <Grid.Column width={11}>
                <Segment>

                  {details}

                </Segment>
              </Grid.Column>
            </Grid.Row>
          </Grid>

      </div>

    )
  }
}

这给了我一个错误:

【问题讨论】:

    标签: javascript reactjs redux react-router


    【解决方案1】:

    如果您的应用程序简单且小型,则无需使用redux。您可以使用组件状态来做到这一点。你应该总是从小处着手,只有在你的应用足够大时才使用 redux。


    现在与您的问题相关,您可以将主要状态保留在&lt;ItemList /&gt; 组件中,并根据从列表中单击的项目将所需数据传递给&lt;ItemContent /&gt; 组件。示例

    class ItemList extends Component {
      constructor(props) {
        super(props);
        this.state = {
         ...
         // you can keep your data here like
         // headings and data for the item content
        }
      }
    
      .
      .
      .
      // your methods
      .
      .
      .
      render() {
        const itemList = //map your list here and
        // provide a click event which will
        // render the respective <ItemContent />
        // may be using an id or some index of the array
        // depends how you want your data structure to be.
        return(
          {itemList}
          // based on which item from the list is clicked
          // you can pass different heading and state
          <ItemContent heading={...} data={...} />
        );
      }
    }
    

    编辑:代码更改。

    class ExpenseList extends Component {
    
      constructor(props) {
        super(props);
        this.state = {
          currentItemId = this.props.expenses[0].uid
        }
      }
    
      handleItemClick = (e) => {
        const uid = e.target.id;
        this.setState({ currentItemId: uid });
      }
    
      details = () => {
        const { expenseList } = this.props.expenses;
        const [ expense ] = expenseList.filter(expense => {
          return expense.uid === this.state.currentItemId;
        });
        return (
          <div>
            <ExpenseDetails expenseProps={expense} />
          </div>
        )
      }
    
      render () {
        const { expenseList } = this.props.expenses;
    
        const list = expenseList.map(expense =>
            <Segment clearing key={expense.uid} >
              <a href="#" id={expense.uid} onClick={this.handleItemClick}>
                {expense.createdAt}
              </a>
              <Button floated='right'>
                Preview / Print
              </Button>
            </Segment>
        )
    
        return (
          <Grid celled='internally'>
            <Grid.Row>
              <Grid.Column width={5}>
                <div>
                  <h1>Your Expense List:</h1>
                  <Button onClick={this.props.loadSamples}>Load Sample Expenses</Button>
                  <Segment.Group raised>
                    {list}
                  </Segment.Group>
                </div>
    
              </Grid.Column>
              <Grid.Column width={11}>
                <Segment>
                  {details()}
                </Segment>
              </Grid.Column>
            </Grid.Row>
          </Grid>
        )
      }
    }
    

    注意:我没有测试过。

    【讨论】:

    • 非常感谢,您能帮我解决那个 onClick 事件吗?如何通过 onClick 将道具传递给&lt;ItemContent /&gt;?用当前代码更新了我的帖子
    • @karolis2017 更新了我的答案。检查它是否适合您。
    【解决方案2】:

    对于一个简单的应用程序,我建议您避免使用 redux(尤其是如果您不熟悉 react)。我会使用 react-router 并为每个具有不同 url 的“屏幕”创建一个组件。将状态存储在该屏幕中,并让所有其他组件使用道具来获取数据和操作。

    你的例子:

    import React, { Component } from 'react';
    import {
      BrowserRouter as Router,
      Switch,
      Route,
      Link,
    } from 'react-router-dom'
    
    import './App.css';
    
    class ExpenseList extends Component {
        render () {
          const {expenses, selectExpense} = this.props;
          return (
            <div>{expenses.map(expense => (
              <div key={expense.id}>
                <h5>{expense.title}</h5>
                <button onClick={selectExpense(expense)}>View Details</button>
              </div>
            ))}</div>
          )
        }
      }
    
    class ExpenseDetail extends Component {
        render () {
          const {expense} = this.props;
          return (
          <div>
            <h1>{expense.title}</h1>
            <p>${expense.amount}</p>
          </div>
          )
        }
      }
    
    
    
    class ExpenseScreen extends Component {
      state = {expenses: [], selectedExpense: null}
    
      loadSamples = () => {
        // fetch from backend here
    
        this.setState({expenses: [
          {id: 1, title: "Expense 1", amount: 1},
          {id: 2, title: "Expense 2", amount: 2},
          {id: 3, title: "Expense 3", amount: 3},
          {id: 4, title: "Expense 4", amount: 4},
        ]})
      }
    
      selectExpense = (expense) => (clickEvent) => {
        this.setState({selectedExpense: expense});
      }
    
      render() {
        return(
        <div className="expense-container">
            <Link to="/about">About</Link>
            <div className="left-col">
              <h1>Your Expense List:</h1>
              <button onClick={this.loadSamples}>Load Sample Expenses</button>
              <ExpenseList expenses={this.state.expenses} selectExpense={this.selectExpense} />
            </div>
            <div className="right-col">
            {this.state.selectedExpense && <ExpenseDetail expense={this.state.selectedExpense} />}
      </div>
      </div>);
      }
    }
    
    
     const About = () => (
        <div>
          <h2>About</h2>
          <Link to="/">Home</Link>
        </div>
      )
    
    class App extends Component {
      render() {
        return (
          <div className="App">
            <Router>
              <Switch>
              <Route path="/" exact component={ExpenseScreen} />
              <Route path="/about" component={About} />
              </Switch>
            </Router>
          </div>
        );
      }
    }
    
    export default App;
    

    【讨论】:

    • 感谢您的回答。对于这种情况,您能否向我展示您的 react-router-dom 代码?如果它们对应不同的 url,如何在一个屏幕上渲染 2 个组件?
    • 你是在建议我在我的帖子中问“我应该创建 组件并嵌套其他组件吗?”
    • 你能更正我发布的代码吗?我尝试使用您的解决方案来解决编译问题,但没有奏效。我只是想看看和理解我的代码的案例和 react-router 的案例。
    • 感谢您的解决方案!
    • 我正在查看那个 react-router 示例,但仍然无法弄清楚如何根据我的情况进行调整。我必须将所有道具传递给我的&lt;ExpenseDetails /&gt; 组件。不仅仅是身份证。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-18
    • 1970-01-01
    • 2022-12-11
    • 2014-04-10
    • 1970-01-01
    相关资源
    最近更新 更多