【问题标题】:Why render is not triggered even the props changed为什么即使道具更改也不会触发渲染
【发布时间】:2017-11-21 11:54:41
【问题描述】:

我已经使用 react+redux 很长时间了,但是你能帮我解决以下情况吗,codepen

const {createStore } = Redux;
const { Provider, connect } = ReactRedux;

const store = createStore((state={name: 'ron'}, action) => {
  switch(action.type) {
    case 'changeName': return {name: action.name};
    default: return state
  }
})

const Person = props => {
  const {name, dispatch} = props
  console.log(`rendering Person due to name changed to ${name}`)
  return (
    <div>
      <p> My name is {name} </p> 
      <button onClick={ () => dispatch({type: 'changeName', name: 'ron'}) } > Change to Ron </button>
      <button onClick={ () => dispatch({type: 'changeName', name: 'john'}) } > Change to John</button>
    </div>  
  )
}

const App = connect(state=>state)(Person)

ReactDOM.render(
  <Provider store={store}><App/></Provider>,
  document.getElementById('root')
);

这是一个简单的反应应用程序,但我无法解释:

  1. 用一个reducer初始化redux store,它的initValue是{name: 'ron'}
  2. 点击Change to ron按钮,会发送{type: 'changeName', name: 'ron'}
  3. 当reducer得到这个动作时,它会生成一个全新的状态{name: 'ron'},虽然值和原来的状态一样,但是它们是不同的身份,应该是不同的。
  4. 如果 props 发生变化,即使值相同,也应该重新渲染功能组件。所以我想渲染函数会被调用,控制台应该输出rendering Person due to...。然而,这并没有发生。

我想知道为什么当 props 标识改变时 react 功能组件拒绝再次渲染(尽管值是相同的)

【问题讨论】:

  • React 检查值的变化并更新虚拟 DOM。如果数据没有变化(即使身份已更改),则不会更新虚拟 DOM,也不会重新渲染
  • 你有纯组件,没有状态,没有副作用,因此如果值没有变化,它不会重新渲染。如果你想让它重新渲染,你应该创建一个 ES6 类样式组件。
  • @JayabalajiJ 但组件应该重新渲染。对?虽然不会有任何 DOM 插入。它至少应该记录问题中所述的陈述
  • @hidden_​​4003 我认为功能组件不是纯组件,我尝试使用普通的有状态组件,仍然是相同的行为。
  • @Ron 功能组件不是纯粹的,这就是它们快速的原因。避免了所有检查以使其快速。这很奇怪,我几乎试图找到 4-5 个小时。我觉得连接的 mapStateToProps 有一些优化,但我找不到。我已为问题加注星标,以便在有人给出问题时得到答案。

标签: reactjs redux


【解决方案1】:

你的connect(state=&gt;state)(Person)我觉得没有错但是很奇怪。

根据文档https://redux.js.org/docs/basics/UsageWithReact.html,您可以将状态和动作调度器分开,通常命名为 mapStateToProps 和 mapDispatchToProps。

所以,我向你推荐这个代码:

const mapStateToProps = state => ({
  user: state.user
})

const mapDispatchToProps = dispatch => ({
  updateName: (name) => dispatch(changeName(name)),
})

class DemoContainer extends Component {
  constructor() {
    super();
  }

  render() {
    return (
      <div>
        <p> My name is {this.props.user.name}</p> 
      <button onClick={ () => this.props.updateName('ron') } > Change to Ron </button>
      <button onClick={ () => this.props.updateName('john') } > Change to John</button>
      </div>
    );
  }

}
const Demo = connect(
  mapStateToProps,
  mapDispatchToProps
)(DemoContainer)

export default Demo

我的减速机:

const initialState = { name: 'John'}

const user = (state = initialState, action) => {
  switch (action.type) {
    case "CHANGE_NAME":
      return {
        name: action.name
      }
    default:
      return state
  }
}

export default user

我的行动:

export const changeName = ( name ) => ({
  type: "CHANGE_NAME",
  name,
})

你可以在这里查看我的所有代码:https://stackblitz.com/edit/react-tchqrg

我有一个组件类,但你也可以像你一样使用带有连接功能的组件。

【讨论】:

    猜你喜欢
    • 2019-03-12
    • 2019-09-05
    • 1970-01-01
    • 1970-01-01
    • 2020-11-21
    • 2019-09-22
    • 1970-01-01
    • 2016-12-10
    • 2013-03-29
    相关资源
    最近更新 更多