使用Redux重新渲染功能组件

时间:2019-08-06 21:20:29

标签: reactjs redux

我对将功能组件与React结合使用感到困惑。

这是我的组件,实现细节并不那么重要:

const Trending = ({ match, actions, trendingPlaces, meConfig }) => {

  const [GeoView, setGeoView] = useState(AcceptCurrentLocationPlaceholder);
  const menuItem = match.params[0];

  console.log('*** Trending ***');

  if (runsOnClient()) {
    useEffect(() => {
      console.log('effect is run');
      if (!requiresGeolocation(menuItem)) return;

      if (meConfig.isCustomLocationSet) {
        setGeoView(
          getComponentForMenuItem(menuItem));
        return;

      }

      if (geolocationServiceIsAvailable()) {
        const getCurrentLocation = async () => {
          try {
            setGeoView(AcceptCurrentLocationPlaceholder);

            const currentPosition = await getCurrentPosition(
              getConfig().googleMaps.currentPositionOptions);

            setGeoView(getComponentForMenuItem(menuItem));

          } catch (err) {
            setGeoView(DeniedCurrentLocationPlaceholder);
          }
        };

        getCurrentLocation();

      } else {
          // Display the view mentioning 'geolocation is not available' and set custom location
      }
    }, [menuItem]);
  }

  // Fetch trending places
  const { fetchTrendingPlaces } = actions;

  useEffect(() => {
    fetchTrendingPlaces();
  }, []);

  return (
    <section id="zp-trending">
      <TrendingMenu match={ match } />
      <div id="zp-trending-body">
        <Route path={'/trending/list'} component={ GeoView } />
        <Route path={'/trending/map'} component={ GeoView } />
        <Route path={'/trending/settings'} component={ TrendingSettings } />
      </div>
    </section>
  );

};


const mapStateToProps = state => {
  return {
    meConfig: state.meConfig,
    trendingPlaces: state.trendingPlaces
  };
};

const mapDispatchToProps = (dispatch) => {
  return {
    actions: bindActionCreators(fetchTrendingPlaces, dispatch)
  }
};

export default connect(mapStateToProps, mapDispatchToProps)(Trending);

当我检查日志时,似乎*** Trending ***的调用不一致。似乎在每次Redux更新之后也会调用它。

那是为什么?

enter image description here

3 个答案:

答案 0 :(得分:2)

问题是bindActionCreators总是返回新的对象或函数。因此,您在每个redux更新中都会得到新的actions

如果要保留嵌套结构,可以执行以下操作

const mapDispatchToProps = (dispatch) => {
  const actions = bindActionCreators(fetchTrendingPlaces, dispatch);
  return () => ({actions})
};

或者您可以展平属性,以便通过浅层相等性检查。

const mapDispatchToProps = {
  fetchTrendingPlaces
}; // pass object to connect

// use in component
const Trending = ({fetchTrendingPlaces /* the rest of your props*/}) => {

答案 1 :(得分:1)

Read the react hooks rules

仅顶层呼叫挂钩

请勿在循环,条件或嵌套函数中调用Hook。相反,请始终在您的React函数的顶层使用挂钩。通过遵循此规则,可以确保每次渲染组件时都以相同的顺序调用Hook。这就是让React在多个useState和useEffect调用之间正确保留Hook的状态的原因。 (如果您感到好奇,我们将在下面对此进行深入说明。)

仅来自React函数的调用挂钩

不要通过常规JavaScript函数调用Hook。相反,您可以:

✅从React函数组件中调用Hook。

✅从自定义挂钩中调用挂钩(我们将在下一页中了解它们)。 通过遵循此规则,可以确保组件的所有状态逻辑从其源代码中都清晰可见。

这是违反规则的代码部分

if (runsOnClient()) {
    useEffect(() => {
      console.log('effect is run');
      if (!requiresGeolocation(menuItem)) return;

      if (meConfig.isCustomLocationSet) {
        setGeoView(
          getComponentForMenuItem(menuItem));
        return;

      }

修复可能会有帮助。

答案 2 :(得分:0)

问题是我在这里使用useState会触发重新渲染。

其他重新渲染的触发原因:

  • 请求趋势项的useEffect,但这是正常的,因为我希望它们在初始渲染时出现。
  • 为react-router传递的match属性。这也是有意的,因为在url更改时会重新呈现组件。

实际上在useEffect中,看来我必须使用useState来获得条件渲染。所以我想这是预期的行为。
UI的行为符合预期,因此我认为必须重新渲染。