Re-randare fortață a unei componente - FlatList

Salut!

Am o problemă cu un FlatList pe care vreau să-l forțez să se randeze după ce sortez un obiect, dar nu reușesc să fac asta. Atașez mai jos detalii despre problemă - sunt în engleză, deoarece am postat și pe alte site-uri internaționale.

I have a jobs app. In my JobsComponent, where I display the jobs, I have added a sort option that allows users to sort the list of jobs by different criteria. The flow is this: 1) I get the jobs from the server -> 2) the user sorts the jobs -> 3) the sorted list of jobs is re-rendered on the screen.

The problem is that step 3) is not working. The actual list of jobs is being sorted (I can see that in the logs), but my FlatList is not being re-rendered.

Below is my JobsComponent.js:

function RenderJobs(props) {
    var json = JSON.parse(props.jobsData);
    var sort_array = [];
    for (var _id in json) {
        sort_array.push({
            _id:_id,
            jobtitle: json[_id].jobtitle,
            company: json[_id].company,
            duration_driving_value:json[_id].duration_driving.value,
            duration_transit_value: json[_id].duration_transit.value,
            duration_walking_value: json[_id].duration_walking.value,
            duration_driving:json[_id].duration_driving.text,
            duration_transit:json[_id].duration_transit.text,
            duration_walking:json[_id].duration_walking.text,
            date: json[_id].date,
            formatedDescription: json[_id].formatedDescription,
            applyUrl: json[_id].applyUrl
        });
    }
    //sort the list based on user selection
    if (props.sortOrder === props.sortArray[0]) {
        sort_array.sort(function(x,y){return new Date(y.date) - new Date(x.date)});
    }
    else if (props.sortOrder === props.sortArray[1]) {
        sort_array.sort(function(x,y){return x.duration_driving_value - y.duration_driving_value});
    }
    else if (props.sortOrder === props.sortArray[2]) {
        sort_array.sort(function(x,y){return x.duration_transit_value - y.duration_transit_value});
    }
    else {
        sort_array.sort(function(x,y){return x.duration_walking_value - y.duration_walking_value});
    }


    const renderJobItem = ({item}) => {
        var  durationCarApi, durationPublicTransportApi, durationWalkApi, formattedApiDate, formattedJobDescription;
        //format data
        return (
            <Panel //custom component used to display each job
                jobTitle={item.jobtitle}
                company={item.company}
                durationCar={durationCarApi}
                durationTram={durationPublicTransportApi}
                durationWalking={durationWalkApi}
                dateAdded={formattedApiDate}
                onPress={() => 
                    {
                    props.navigation.navigate('JobDetails', {
                        jobTitle: item.jobtitle,
                        company: item.company,
                        durationCar: durationCarApi,
                        durationTram: durationPublicTransportApi,
                        durationWalking: durationWalkApi,
                        jobDescription: formattedJobDescription,
                        applyUrl: item.applyUrl
                })
                    }
                }/>
        );
    }

    //handle loading/error scenarios
        return (
            <FlatList 
                    data={sort_array}
                    extraData={props.sortOrderChanged}
                    renderItem={renderJobItem}
                    keyExtractor={(item, index) => index.toString()}
                    style={{marginTop: 10}}
                    />
        );

}

class Jobs extends Component {

    constructor(props) {
        super(props);
        this.state = { 
            jobTitle: this.props.navigation.getParam('jobTitle', ''),
            address: this.props.navigation.getParam('address', 'error'),
            sortOrderChanged: false,
            sortArray: [0,1,2,3],
            selectedSortOrder: 1 //default is sort_driving
         };
      }

    componentDidMount() {

        handleSorting = (dataFromChild) => {
            console.log('Sort order clicked: ' + dataFromChild);
            this.RBSheet.close();
            this.setState({
                sortOrderChanged: !this.state.sortOrderChanged,
                selectedSortOrder: dataFromChild
            });
    }

    render() {
        return(
            <ScrollView contentContainerStyle={styles.bkg}>
                <RenderJobs 
                    jobsData={JSON.stringify(this.props.jobs.jobs)}
                    isLoading={this.props.jobs.isLoading}
                    errMess={this.props.jobs.errMess}
                    navigation={this.props.navigation}
                    sortOrder={this.state.selectedSortOrder}
                    sortArray={this.state.sortArray}
                    sortOrderChanged={this.state.sortOrderChanged} 
                    />
                <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
                    <RBSheet //custom component used to render the sorting options
                        ref={ref => {this.RBSheet = ref;}}
                        height={200}
                        duration={250}
                        customStyles={{
                            container: {
                            justifyContent: "center",
                            alignItems: "center"
                        }
                    }}>
                    <SortSheet //this is the child component used to render the sorting options
                        sortOrder={this.handleSorting}
                        sortArray={this.state.sortArray}/>
                    </RBSheet>
                </View>
            </ScrollView>
        )
    }
}

What I have tried

  1. I have a flag, sortOrderChanged, set in my state. Whenever the user selects a sorting option, I change this flag in my componentDidMount() method whenever the sort order changes:
this.setState({
                sortOrderChanged: !this.state.sortOrderChanged,                 
                selectedSortOrder: dataFromChild             
});

and pass it to FlatList as extraData:

<FlatList                      
            data={sort_array}                     
            extraData={props.sortOrderChanged}                     
            renderItem={renderJobItem}                     
            keyExtractor={(item, index) => index.toString()}                     
            style={{marginTop: 10}}                     
        /> 

  1. I moved my jobs data to the local state as follows:

In my JobsComponent, I changed my state to contain the jobs data
this.state = { jobs: JSON.stringify(this.props.jobs.jobs), }

I passed the state to the component that includes the FlatList
<RenderJobs sortOrderProps={this.state} />

and passed sortOrderProps to extraData.
<FlatList extraData={props.sortOrderProps}/>

Din păcate, niciuna dintre soluțiile de mai sus nu funcționează. Aveți vreo idee de ce? :slight_smile:

Mulțumesc!

Fa un efort si pune tot codul corect in tags de code. E foarte greu de urmarit. Ar fi bine-venit si un codesandbox/jsfiddle etc.

3 Likes

Scuze, nu mi-am dat seama că se salvase cu formatarea greșită. Am modificat.

keyExtractor: Used to extract a unique key for a given item at the specified index. Key is used for caching and as the react key to track item re-ordering.

Try this:

keyExtractor={(item, index) => item._id}
5 Likes

Acolo era buba. Mersi mult pentru ajutor! :raised_hands: