繁体   English   中英

Redux-thunk调度一个动作并等待重新渲染

[英]Redux-thunk dispatch an action and wait for re-render

import React from "react";
import { render } from "react-dom";
import { createStore, applyMiddleware } from "redux";
import { Provider, connect } from "react-redux";
import thunk from "redux-thunk";

const disabled = (state = true, action) => {
  return action.type === "TOGGLE" ? !state : state;
};

class Button extends React.Component {
  componentDidUpdate(prevProps) {
    if (prevProps.disabled !== this.props.disabled && !this.props.disabled) {
      //  this.ref.focus();  // uncomment this to see the desired effect
    }
  }
  render() {
    const { props } = this;
    console.log("rendering", props.value);
    return (
      <div>
        <input
          type="checkbox"
          onClick={() => {
            props.toggle();
            this.ref.focus(); // doesn't work
          }}
        />
        <input
          disabled={props.disabled}
          ref={ref => {
            this.ref = ref;
          }}
        />
      </div>
    );
  }
}

const toggle = () => ({
  type: "TOGGLE"
});

const A = connect(state => ({ disabled: state }), { toggle })(Button);

const App = () => (
  <Provider store={createStore(disabled, applyMiddleware(thunk))}>
    <A />
  </Provider>
);

render(<App />, document.getElementById("root"));

编辑redux-thunk-promise

我想在选中复选框时关注input 但是,必须在使用props.disabled === false重新呈现组件之后调用this.ref.focus() ,因为无法聚焦具有disabled prop的input

如果我在componentDidUpdate执行逻辑,我就能实现我想要的。 但这不是一个干净的解决方案,因为逻辑特定于onClick处理程序而不是生命周期事件。

有没有其他方法可以实现这一目标? (最好使用工作代码框示例)

我认为最好的办法是不依靠refs use state来管理焦点。

此解决方案使用输入上的autoFocus prop,并在复选框的状态更改时修改它。

import React from "react";
import { render } from "react-dom";
import { createStore, applyMiddleware } from "redux";
import { Provider, connect } from "react-redux";
import thunk from "redux-thunk";

const disabled = (state = true, action) => {
  return action.type === "TOGGLE" ? !state : state;
};

class Button extends React.Component {
  state = {
    checked: false,
    focus: false
  };
  componentDidUpdate(prevProps, prevState) {
    if (prevState.checked !== this.state.checked) {
      this.props.toggle();
      this.setState({
        focus: this.state.checked
      });
    }
  }
  render() {
    const { props } = this;
    const { checked, focus } = this.state;
    console.log("rendering", props.value, checked);
    return (
      <div>
        <input
          type="checkbox"
          checked={checked}
          onClick={({ target }) => {
            this.setState({ checked: target.checked });
          }}
        />
        <input key={`input_${checked}`} autoFocus={focus} />
      </div>
    );
  }
}

const toggle = () => ({
  type: "TOGGLE"
});

const A = connect(state => ({ disabled: state }), { toggle })(Button);

const App = () => (
  <Provider store={createStore(disabled, applyMiddleware(thunk))}>
    <A />
  </Provider>
);

render(<App />, document.getElementById("root"));

编辑redux-thunk-promise


我不知道为什么,但是当组件先前被禁用时更改autoFocus prop不会触发重新渲染的输入。 所以我还在输入中添加了一个键以强制它。

这是一个假设情况和REACT中的一个开放问题(同时不是),因为它与自动对焦的HTML规范一致( https://developer.mozilla.org/en-US/docs/Web/HTML/Element / input #Attributes #autofocus )。 焦点是装饰性的非常棘手的事情之一,因为它是共享的全球状态的一部分。 如果2个不相关的组件声明它们应该集中在一个渲染过程中,谁是对的? 因此,REACT为您提供了自己管理该状态的钩子,但它不会为您做到这一点(因此,您正在使用的工作就在那里)。

但是如果REACT添加了关注渲染的选项(可能只是autoFocusOnRender),那就好了,如果有多个事情需要立即聚焦,那么让文档警告人们行为。 理想情况下,这不会发生,因为具有良好UX的应用程序将具有在不同输入上调用autoFocusOnRender的特定条件。

我建议你做的是最好的做法:)。 希望我们在REACT中对此进行改进。

我认为,在执行focus()调用之前,您可以放心更新的Redux state数据,因为数据流:

  1. 发送异步操作toggleThunk ,并等待其解析
  2. then调度同步动作来更新state (新state数据),并等待其解析(?)
  3. then focus()你的参考

https://codesandbox.io/s/r57v8r39om

编辑redux-thunk-promise

请注意,在您的OP中,您的toggle()动作创建者不是thunk。 此外,强制执行您的thunk返回Promise是一个很好的规则,这样您就可以按照您描述的方式控制数据流。

import React from "react";
import { render } from "react-dom";
import { createStore, applyMiddleware } from "redux";
import { Provider, connect } from "react-redux";
import thunk from "redux-thunk";

const disabled = (state = true, action) => {
  return action.type === "TOGGLE" ? !state : state;
};

class Button extends React.Component {
  textInput = React.createRef();

  handleClick = () => {
    const { toggleThunk } = this.props;
    toggleThunk().then(() => {
      this.textInput.current.focus();
    });
  };

  render() {
    const { disabled, value } = this.props;
    return (
      <div>
        <input type="checkbox" onClick={this.handleClick} />
        <input disabled={disabled} ref={this.textInput} />
      </div>
    );
  }
}

// Action
const toggle = () => ({
  type: "TOGGLE"
});

// Thunk
const toggleThunk = () => dispatch => {
  // Do your async call().then...
  return Promise.resolve().then(() => dispatch(toggle()));
};

const A = connect(state => ({ disabled: state }), { toggleThunk })(Button);

const App = () => (
  <Provider store={createStore(disabled, applyMiddleware(thunk))}>
    <A />
  </Provider>
);

render(<App />, document.getElementById("root"));

您可以使用prop和ref来管理它。 ref将避免重新输入输入(即autoFocus工作):

import React, { Component } from "react";
import { render } from "react-dom";
import { createStore, applyMiddleware } from "redux";
import { Provider, connect } from "react-redux";
import thunk from "redux-thunk";

const disabled = (state = true, action) => {
  return action.type === "TOGGLE" ? !state : state;
};

class Button extends Component {

  componentDidUpdate(prevProps) {
    if (!this.props.disabled && prevProps.disabled) {
      this.ref.focus();
    }
  }

  render() {
    const { disabled } = this.props;
    return (
      <div>
        <input
          type="checkbox"
          checked={!disabled}
          onClick={() => {
            this.props.toggle();
          }}
        />
        <input
          disabled={disabled}
          ref={ref => {
            this.ref = ref;
          }}
        />
      </div>
    );
  }
}

const toggle = () => ({
  type: "TOGGLE"
});

const A = connect(state => ({ disabled: state }), { toggle })(Button);

const App = () => (
  <Provider store={createStore(disabled, applyMiddleware(thunk))}>
    <A />
  </Provider>
);

render(<App />, document.getElementById("root"));

编辑redux-thunk-promise

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM