【问题标题】:React not rerendering props when render function is provided提供渲染功能时反应不重新渲染道具
【发布时间】:2017-12-10 12:34:23
【问题描述】:

我无法理解为什么在提供渲染功能时不进行渲染,而不是直接返回 JSX。

这是我的 InputBox 组件示例:

export default React => {
  const InputBox = ({ city, setCity, setTime }) => {
    const onInputEnter = createOnInputEnter({ city, setCity, setTime, getCityTime })

    return (
        <div className='InputBox'>
          <input
            defaultValue={city}
            onKeyPress={onInputEnter}
            onFocus={moveFocusAtEnd}
            autoFocus />
        </div>
      )
  }

  return InputBox
}

在这种情况下,每次我更改城市的 redux 状态时都会重新渲染城市。

export default React => {
  const InputBox = ({ city, setCity, setTime }) => {
    const onInputEnter = createOnInputEnter({ city, setCity, setTime, getCityTime })

    const componentDidMount = async () => {
      const { city: resultCity, time: resultTime } = await getCityTime(city)

      setCity(resultCity)
      setTime(resultTime)
    }

    const render = () => {
      return (
        <div className='InputBox'>
          <input
            defaultValue={city}
            onKeyPress={onInputEnter}
            onFocus={moveFocusAtEnd}
            autoFocus />
        </div>
      )
    }

    return { render, componentDidMount }
  }

  return InputBox
}

在这个例子中,城市只被传递一次,当 redux 状态改变时不会重新渲染。

我想使用后一个示例,因为我使用 componentDidMount 方法进行初始化。

我在这个例子中使用了 React 和 React-Redux。

这就是我的 InputBox 容器的样子:

import createInputBox from '../components/InputBox.js'
import { connect } from 'react-redux'

...

export default React => {
  const InputBox = createInputBox(React)

  const InputBoxWithReduxStore = connect(
    ({ city }) => ({ city }),
    mapDispatchToProps
  )(InputBox)

  return InputBoxWithReduxStore
}

编辑:

我包含代码 sn-p 以显示 createOnInputEnter 函数的实现

function createOnInputEnter ({ city, setCity, setTime, getCityTime }) {
  return async ({ key, target }) => {
    if (key === 'Enter') {
      try {
        const inputCity = target.value

        setTime('...')

        const { city: resultCity, time: resultTime } = await getCityTime(inputCity)

        setCity(resultCity)
        setTime(resultTime)
      } catch (err) {
        const { city: resultCity, time: resultTime } = await getCityTime(city)

        setCity(resultCity)
        setTime(resultTime)
      }
    }
  }
}

正如@zarcode 建议使用 React.Component,它不符合我的要求。因为我使用无类组件。更多关于 Mixin 部分:https://gist.github.com/jquense/47bbd2613e0b03d7e51c

【问题讨论】:

  • 请添加到codesandbox.io/s/new
  • @PeterParada,哪里没有发生渲染
  • @ShubhamKhatri 关于 createOnInputEnter 函数的 catch 子句 - city 仍然是默认的,即使您在 redux 状态下更改它。

标签: javascript reactjs redux react-redux


【解决方案1】:

componentDidMount 只会调用一次,并且也可以自下而上地工作。 因此,对于每次状态更改的渲染,您都可以使用 componentWillReceieveprops。

【讨论】:

  • 这个解决方案的问题是我需要从位于 componentWillReceiveProps 之外的 createOnInputEnter 函数内部访问更新的 props.city。也许我弄错了,你能告诉我一个示范性的例子,这如何解决在 createOnInputEnter 函数中访问更新的城市属性的问题?我将编辑代码来展示这个函数的实现。
  • 另外,componentDidMount 只被调用一次也没关系,我只将它用于初始化,因此希望只被调用一次。
【解决方案2】:

您的第一个示例是一个功能组件,如果您不需要组件生命周期方法(如 componentDidMount),您可以使用它。

您的第二个示例是功能组件与生命周期方法的某种混合,不确定是否可以工作,从未尝试过。 相反,如果您想在组件中使用生命周期方法,我建议您使用扩展 React.Component 的类组件。它应该看起来像这样:

...
import {Component} from "react";

export default class InputBox extends Component {
   onInputEnter = () => { 
       const { city, setCity, setTime } = this.props;
       createOnInputEnter({ city, setCity, setTime, getCityTime })
   }

   async componentDidMount() {
     const { city, setCity, setTime } = this.props;
     const { city: resultCity, time: resultTime } = await getCityTime(city)

     setCity(resultCity)
     setTime(resultTime)
   }

   render(){
     return (
       <div className='InputBox'>
         <input
           defaultValue={city}
           onKeyPress={onInputEnter}
           onFocus={moveFocusAtEnd}
           autoFocus />
       </div>
     )
   }

}

【讨论】:

【解决方案3】:

在第一种情况下,const onInputEnter = createOnInputEnter({ city, setCity, setTime, getCityTime }) 在组件的渲染方法中,因为它是一个功能组件。

我不明白这个概念是如何工作的,但是第二个例子与第一个例子一样,你需要做这样的事情:

export default React => {
  const InputBox = ({ city, setCity, setTime }) => {

    const componentDidMount = async () => {
      const { city: resultCity, time: resultTime } = await getCityTime(city)

      setCity(resultCity)
      setTime(resultTime)
    }

    const render = () => {
    const { city, setCity, setTime } = this.props;
    const onInputEnter = createOnInputEnter({ city, setCity, setTime, getCityTime })
      return (
        <div className='InputBox'>
          <input
            defaultValue={city}
            onKeyPress={onInputEnter}
            onFocus={moveFocusAtEnd}
            autoFocus />
        </div>
      )
    }

    return { render, componentDidMount }
  }

  return InputBox
}

虽然我不确定这是否是在此处访问渲染内部道具的方式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-19
    • 1970-01-01
    • 2021-12-22
    • 2020-10-21
    • 2023-02-15
    • 2019-03-02
    相关资源
    最近更新 更多