React Native - Stan zmieniony w dziecku, jak zaktualizować Parent?

Nov 25 2020

obecnie zmieniam stan w moim komponencie podrzędnym, a teraz chcę zaktualizować mojego rodzica. Początkowo przekazuję dane od rodzica dziecku, następnie w dziecku zmieniam stan. kiedy to robię, nic się nie dzieje w aplikacji, ponieważ rodzic nadal nie jest aktualizowany, ale kiedy ponownie ładuję aplikację, wprowadzone zmiany są aktualizowane.

Używam również nawigacji reagowania, aby przejść z ekranu rodzica do ekranu dziecka.

Oto mój kod:

Ekran nadrzędny:

function PostsScreen({navigation}) {

const [posts, setPosts] = useState([]);
const [error, setError] = useState(false);
const [loading, setLoading] = useState(false);

const loadPosts = async () => {
setLoading(true);
const response = await postsApi.getPosts();
setLoading(false);

if (!response.ok) return setError(true);

setError(false);
setPosts(response.data);
};

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

return(
<ActivityIndicator visible={loading} />
<FlatList
      data={posts}
      keyExtractor={(post) => post.id.toString()}
      renderItem={({ item }) => (
        <Card
          title={item.title}
          subTitle={item.subTitle}
          onPress={() => 
          navigation.navigate(routes.POST_DETAILS,item)}
        />
      )}
    />
  );
  }

Ekran podrzędny:

function PostDetailsScreen({ route }) {
const post = route.params;
const { user} = useAuth();

const [addedToLikes, setAddedToLikes] = useState(post.isLiked);
const[likesCount,setLikesCount]=useState(post.likesCount)

const addToLikes = (PostId,userId) => {
postsApi.likePost({PostId,userId});
setAddedToLikes(!addedToLikes);
};

let show_likes="";
if(addedToLikes){
show_likes=(likesCount >1)?(("Liked by you")+" and "+(likesCount - 1)+((likesCount ==2)?( " 
other"):(" others"))):("Liked by you");
}else if(likesCount >0){
show_likes=(likesCount ==1)?(likesCount+ " like"):(likesCount + " likes");
}

return(
<TouchableOpacity onPress={() => {addToLikes(post.id,user.id)}}>
              {addedToLikes?<MaterialCommunityIcons
              name="heart"
            />:<MaterialCommunityIcons
                name="heart-outline"
              />}
</TouchableOpacity>

<View><TextInput>{show_likes}</TextInput></View>

)}

Jak zaktualizować, jeśli post jestLiked i LikeCount w komponencie nadrzędnym?

Nie używam też Redux.

Aktualizacja :

Próbowałem wykonać następujące czynności, ale nadal pojawia się błąd.

Ekran nadrzędny:

function PostsScreen({ navigation }) {
  const [posts, setPosts] = useState([]);
  const [error, setError] = useState(false);
  const [loading, setLoading] = useState(false);

  const loadPosts = async () => {
    setLoading(true);
    const response = await postsApi.getPosts();
    setLoading(false);

    if (!response.ok) return setError(true);

    setError(false);
    setPosts(response.data);
  };

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

  const [addedToLikes, setAddedToLikes] = useState(post.isLiked);

  const addToLikes = (PostId, userId) => {
    postsApi.likePost({ PostId, userId });
    setAddedToLikes(!addedToLikes);
  };

  const { user } = useAuth();

  return (
    <React.Fragment>
      <ActivityIndicator visible={loading} />
      <FlatList
        data={posts}
        keyExtractor={post => post.id.toString()}
        renderItem={({ item }) => (
          <Card
            title={item.title}
            subTitle={item.subTitle}
            onPress={() => navigation.navigate(routes.POST_DETAILS, item)}
          />
        )}
      />
      <PostDetailsScreen addToLikes={addToLikes(posts.id, user.id)} />
    </React.Fragment>
  );
}

Ekran podrzędny:

function PostDetailsScreen({ route, addedToLikes, addToLikes }) {
  const post = route.params;

  const [likesCount, setLikesCount] = useState(post.likesCount);

  let show_likes = "";
  if (addedToLikes) {
    show_likes =
      likesCount > 1
        ? "Liked by you" + " and " + (likesCount - 1) + (likesCount == 2 ? " other" : " others")
        : "Liked by you";
  } else if (likesCount > 0) {
    show_likes = likesCount == 1 ? likesCount + " like" : likesCount + " likes";
  }

  return (
    <React.Fragment>
      <TouchableOpacity
        onPress={() => {
          addToLikes;
        }}
      >
        {addedToLikes ? <MaterialCommunityIcons name="heart" /> : <MaterialCommunityIcons name="heart-outline" />}
      </TouchableOpacity>

      <View>
        <TextInput>{show_likes}</TextInput>
      </View>
    </React.Fragment>
  );
}

Odpowiedzi

1 LeslieAlldridge Nov 25 2020 at 08:53

Bez korzystania z jakiejś formy współdzielonego stanu, takiej jak Redux, najlepszym sposobem osiągnięcia pożądanego wyniku jest podjęcie decyzji o strukturze komponentów.

Wygląda na to, że masz taką strukturę:

Rodzic (nie wie o likes) -> Dziecko (wie o likes)

Ale chcesz czegoś takiego:

Rodzic (wie o likes) -> Dziecko (interakcja z likes)

Dlatego zalecam, aby Twój statekomponent nadrzędny śledził isLikedi likesCount. Rodzic przekaże również procedurę obsługi metody do składnika potomnego, takiego jak addToLikes(post.id,user.id).

Przykładowy kod:

import React from 'react';

class Parent extends React.Component{
    constructor(props){
        super(props);
        this.state = {
            data: null
        }
    }

    handleCallback = (childData) =>{
        this.setState({data: childData})
    }

    render(){
        const {data} = this.state;
        return(
            <div>
                <Child parentCallback = {this.handleCallback}/>
                {data}
            </div>
        )
    }
}

class Child extends React.Component{
  
    onTrigger = (event) => {
        this.props.parentCallback("Data from child");
        event.preventDefault();
    }

    render(){
        return(
        <div>
            <form onSubmit = {this.onTrigger}>
                <input type = "submit" value = "Submit"/>
            </form>
        </div>
        )
    }
}

export default Parent;