如何基于多个其他状态设置 React 组件的状态?



>我正在处理一个带有录制音频按钮的屏幕。根据录制的状态,我想隐藏同一屏幕上的文本输入框。为了隐藏它,我正在更改不透明度并使其不可编辑。

我正在根据另外 2 种状态(isRecordingisRecorded)设置 2 种状态(isTextInputEditabletextInputOpacity)。我当前的代码有问题,因为 useState 是异步的,当我在函数中执行检查时,isRecording 和 isRecorded 的状态setTextInputVisibility没有更新。

任何提示都会有所帮助,谢谢。

const [isTextInputEditable, setIsTextInputEditable] = useState(true);
const [textInputOpacity, setTextInputOpacity] = useState(1);
const [isRecording, setIsRecording] = useState(false);
const [isRecorded, setIsRecorded] = useState(false);
const onRecord = () => {
if (!isRecording) {
console.log("Started recording audio")
setIsRecording(true)
setIsRecorded(false)
}
else {
console.log("Stopped recording audio")
setIsRecording(false)
setIsRecorded(true)
}
setTextInputVisibility();
}
const setTextInputVisibility = () => {
if (!isRecording && !isRecorded){  
setIsTextInputEditable(true)
setTextInputOpacity(1)
console.log("Text input visible")
}
else{
setIsTextInputEditable(false)
setTextInputOpacity(0)
console.log("Text input invisible")
}
}

您不必使用状态来隐藏文本输入 由于隐藏文本输入取决于isRecordingisRecorded

你可以做这样的事情

const [isRecording, setIsRecording] = useState(false);
const [isRecorded, setIsRecorded] = useState(false);
const onRecord = () => {
if (!isRecording) {
console.log("Started recording audio")
setIsRecording(true)
setIsRecorded(false)
}
else {
console.log("Stopped recording audio")
setIsRecording(false)
setIsRecorded(true)
}
setTextInputVisibility();
}
const isTextInputEditable = !isRecording && !isRecorded
const textInputOpacity = (!isRecording && !isRecorded) ? 1 : 0

return (
<View>
{/* Your code goes here */}
<TextInput 
disabled={!isTextInputEditable}
style={{ ...styles.inputStyles, opacity : textInputOpacity }}
/>
</View>
)

我认为您的问题不是由状态的异步性质引起的,而是由冲突的条件引起的:

if (!isRecording && !isRecorded){ ... } // this is the problem

以前,在onRecord函数中,您可以按如下方式设置isRecordingisRecorded

setIsRecording(true)
setIsRecorded(false)
// or the other way around

这个原因!isRecording && !isRecorded永远无法评估true,因为,总会有他们中的任何一个都会被false的情况!所以isTextInputEditabletextInputOpacity永远是假的和 0!

可能的解决方法:

const setTextInputVisibility = () => {
if (!isRecording) { // <- only depends on one state condition
setIsTextInputEditable(true);
setTextInputOpacity(1);
console.log("Text input visible");
} else {
setIsTextInputEditable(false);
setTextInputOpacity(0);
console.log("Text input invisible");
}
};

同样,正如 tomleb Rightful 在评论中指出的那样,如何管理状态是这里真正的问题,例如,您可能根本不需要状态textInputOpacity因为它基本上与isTextInputEditable相同,并且它们都服务于相同的目的。

查看沙盒。

谢谢大家的回答,这些回答帮助我了解了正在发生的事情。

正如@Enfield所提到的,问题不在于UseState的异步性质。有些条件是错误的,我定义了太多不必要的状态。

我只使用一种状态来解决它,该状态为不同的情况使用枚举,这对于条件渲染非常方便。然后,按照@poojan的建议,我将文本输入可见性变量基于我之前创建的记录状态。此处无需使用效果进行重新渲染。

你可以在这里找到一个工作示例

enum RecordingStatus {
RECORDING = "recording",
RECORDED = "recorded",
NOTRECORDED = "notRecorded",
PLAYING = "playing"
}
export default function App() {
const [recordingStatus, setRecordingStatus] = React.useState<RecordingStatus>(
RecordingStatus.NOTRECORDED
);
const isTextInputEnabled = recordingStatus === RecordingStatus.NOTRECORDED;
const textInputOpacity = isTextInputEnabled ? 1 : 0;
const onRecord = () => {
if (recordingStatus === RecordingStatus.NOTRECORDED) {
console.log("Started recording audio");
setRecordingStatus(RecordingStatus.RECORDING);
} else if (recordingStatus === RecordingStatus.RECORDING) {
console.log("Stopped recording audio");
setRecordingStatus(RecordingStatus.RECORDED);
} else if (recordingStatus === RecordingStatus.RECORDED) {
console.log("Audio playing");
setRecordingStatus(RecordingStatus.PLAYING);
} else if (recordingStatus === RecordingStatus.PLAYING) {
console.log("Audio stopped");
setRecordingStatus(RecordingStatus.RECORDED);
}
};
const onCancel = () => {
console.log("Cancel recording");
setRecordingStatus(RecordingStatus.NOTRECORDED);
};
return (
<div>
<div>isTextInputEditable: {isTextInputEnabled ? "true" : "false"}</div>
<div>textInputOpacity: {textInputOpacity}</div>
<div>recordingStatus: {recordingStatus}</div>
<button onClick={onRecord}>change</button>
<button
disabled={!(recordingStatus === RecordingStatus.RECORDED)}
onClick={onCancel}
>
cancel
</button>
</div>
);
}

最新更新