[英]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"));
我想在选中复选框时关注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"));
我不知道为什么,但是当组件先前被禁用时更改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
数据,因为数据流:
toggleThunk
,并等待其解析 then
调度同步动作来更新state
(新state
数据),并等待其解析(?) then
focus()
你的参考 https://codesandbox.io/s/r57v8r39om
请注意,在您的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"));
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.