【问题标题】:How do you change a a state object after receiving it from another non-child component?从另一个非子组件接收到状态对象后,如何更改它?
【发布时间】:2021-03-04 13:56:23
【问题描述】:

我目前正在使用 react native 开发应用程序,但遇到了一个特定问题。我的应用程序有 3 个主屏幕。一是在存储在设备上的列表中简要显示数据,二是从用户输入新数据并存储,三是显示数据但更详细。所有这些屏幕都包含在我的 app.js 文件中,其中我有我的 NavigationContainer。在我的主屏幕组件(简要显示数据的组件)中,我有一个名为 list 的状态对象,我在其中加载用户保存的所有输入。当用户点击一个按钮时,他被带到上述输入屏幕。在这里,我有滑块,用户可以在其中设置他/她想要的输入,还有一个按钮来保存输入。当点击保存按钮时,数据应该被保存,用户被带回主屏幕,并且用户应该看到他/她所做的输入。

现在到我试图提出的尝试解决方案。我尝试将输入作为 navigation.navigate() 方法的对象参数传入。在主屏幕组件上,我试图在 useEffect() 钩子中捕获对象,但首先检查它是否未定义(因为它是主屏幕,我不应该在用户打开时在开头添加一个空对象应用程序)。我也尝试更新列表对象的状态,但它不起作用。应用程序崩溃,日志中未显示任何错误。此外,我无法将输入保存到输入组件中的设备,因为我需要将它们添加到先前保存的列表的其余部分,然后保存该新列表。我想在输入屏幕类中使列表对象成为状态对象,但我需要主屏幕的列表,因为我在那里显示所有数据。我也无法将按钮的 onPress 事件向上传递,因为它们是不相关的组件。我也不能将状态放在 app.js 类中,因为从我收集到的信息中,我不能将函数作为道具传递给堆栈导航器的屏幕组件。通过研究这个问题,我发现使用 redux 可以成为更新任何组件状态的解决方案。但是,我认为这种解决方案有点矫枉过正,因为我只需要处理一个状态对象,而且我没有很多组件使用它。

最好的方法是什么?我使用 useEffect 钩子错了吗?我应该使用其他挂钩来更新列表吗?如何更新值,然后设置屏幕导航到的状态?

代码:

function PreviousTasksScreen(props) {
prevList = [];
const [list, setList] = useState(prevList);

getCurrentDate = () => {
var date = new Date().getDate();
var month = new Date().getMonth() + 1;
var year = new Date().getFullYear();

return date + "-" + month + "-" + year; //format: dd-mm-yyyy;
};

getTotalRating = (ratingList) => {
let total = ratingList.reduce(function (prev, cur) {
  return prev + cur.value;
}, 0);

return total;
/*ratingList.array.forEach(element => {
  element.value
});*/
};

/*const save = async () => {
try {
  await AsyncStorage.setItem("List", prevList);
} catch (err) {
  alert(err);
}
};
const load = async () => {
try {
  let list = await AsyncStorage.getItem("List");

  if (list !== null) {
    setList(list);
  }
} catch (err) {
  alert(err);
}
};*/

useEffect(() => {
if (typeof props.route.params !== "undefined") {
  console.log("has the parent");
  if (typeof props.route.params.otherParam !== "undefined") {
    let par = props.route.params.otherParam;
    console.log("has the object");
    prevList = [...list];
    prevList.push(par);
    //console.log(prevList);
    //setList(prevList);

    //save();

    //console.log(list);
  }
} else {
  //load();
  console.log("prarameter is undefined");
}
//load();

console.log("useEffect called");
setList(prevList);
});

return (
<SafeAreaView style={styles.container}>
  <Button
    title="Add Review"
    onPress={() => props.navigation.navigate("addReview")}
  ></Button>

  <FlatList
    data={list}
    renderItem={({ item }) => (
      <ListItem
        date={item.date}
        rating={item.totalRating}
        id={item.key}
        nav={props.navigation}
      />
    )}
  />
  </SafeAreaView>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
justifyContent: "center",
},

item: {
width: "100%",
height: 70,
},

title: {
fontSize: 20,
left: 20,
},
});

export default PreviousTasksScreen;

对于输入屏幕:

class ReviewTasksScreen extends Component {
state = {
myList: [
  { id: 1, title: "test1", value: 3 },
  { id: 2, title: "test2", value: 5 },
  { id: 3, title: "test3", value: 2 },
],

//prevReviewLists: [],
};

constructor() {
super();
console.log("App-Constructor");
}

/*printList = () => {
console.log(list);
};*/

handleCallback = (reviewItem) => {
const myList = [...this.state.myList];
const index = myList.indexOf(reviewItem);
myList[index] = { ...reviewItem };
this.setState({ myList });
//setList({ lst });
};

deleteExtra = (rItem) => {
delete rItem.title;
};

addToList = () => {


  const saveList = this.state.myList.map(({ id, value }) => ({ id, value }));
  //console.log(saveList);
  let myObject = {
  date: "",
  key: 1,
  myList: "",
  totalRating: 0,
  };

  myObject.date = getCurrentDate();
  myObject.totalRating = getTotalRating(saveList);
  myObject.myList = saveList;
  console.log(myObject);

  this.props.navigation.navigate("list", {
    otherParam: myObject,
  });
};

render() {
return (
  <ScrollView>
    {this.state.myList.map((item) => (
      <ReviewItem
        key={item.id}
        id={item.id}
        title={item.title}
        value={item.value}
        item={item}
        handleChange={this.handleCallback}
      />
    ))}

    <Button title="Save" onPress={this.addToList}></Button>
  </ScrollView>
);
}
}

export default ReviewTasksScreen;

【问题讨论】:

  • 你最好使用redux来达到这个目的。
  • 在此处分享您的代码。没有人会读你的故事。
  • 我已经添加了代码。我认为这是一个我没有看到的简单逻辑错误,这就是我最初没有包含代码的原因。我还尝试提供尽可能多的背景信息,并希望展示我尝试解决问题的所有不同方式,抱歉问题太长了。

标签: javascript reactjs react-native


【解决方案1】:

事实证明,我可以使用“useContext()”功能从非分层组件访问对象。 YouTube 有很多关于这个功能的好视频。我希望这对任何与我有类似问题的人有所帮助。如果您没有复杂的状态和状态转换,则不需要使用 redux。

【讨论】:

    猜你喜欢
    • 2020-06-05
    • 2021-10-18
    • 1970-01-01
    • 1970-01-01
    • 2020-10-12
    • 1970-01-01
    • 2020-08-15
    • 2020-04-26
    • 1970-01-01
    相关资源
    最近更新 更多