question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

NestedRow not updating on state change

See original GitHub issue

I have a NestedListView that have checkboxes (using TouchableOpacity with Image that looks like a checkbox) in all of them.

When I click on the Checkbox in each NestedRow, the state changes as output in the componentWillUpdate and render methods, but the NestedRow itself isn’t updating.

Here is a quick example I’ve whipped up from another issue. The selected array in the state is like

[
  {
    parent: false, //parent 0 value
    child: [
      false, // child 0 value
      false
    ]
  }
...etc
]
const generateXNumItems = (pid, numItems, prefix) => {
    const items = []
    let i
    for (i = 0; i < numItems; i++) {
        items.push({
            name: `${prefix}.${i}`,
            childId: i,
            parentId: pid,
        })
    }

    return items
}

const data = [
    {
        name: 'Item level 1.1',
        parentId: 0,
        descendants: generateXNumItems(0, 10, 'Item level 1.1'),
    },
    {
        name: 'Item level 1.2',
        parentId: 1,
        descendants: generateXNumItems(1, 5, 'Item level 1.1'),
    },
    {
        name: 'Item level 1.3',
        parentId: 2,
        descendants: generateXNumItems(2, 2, 'Item level 1.3'),
    },
]

const colorLevels = {
    [0]: 'white',
    [1]: 'blue',
    [2]: 'green',
    [3]: 'red',
}

const styles = StyleSheet.create({
    container: { flex: 1, backgroundColor: 'rgb(255, 255, 255)', padding: 15 },
    node: {
        flex: 1,
        padding: 10,
        borderWidth: 1,
        borderColor: 'rgb(0, 0, 0)',
    },
})

class ExampleApp extends Component {
    constructor(props) {
        // console.log(JSON.stringify(data));
        super(props)
        this.state = {
            selected: []
        }
    }

    componentWillMount() {
        let selected = data.map(element => {
            return {
                parent: false,
                child: Array(element.descendants.length).fill(false)
            }
        })

        // console.log(JSON.stringify(selected));
        this.setState({
            ... this.state,
            selected: selected
        });
    }

    toggleChecked(pid, cid = -1) {
        let a = this.state.selected.slice(); //creates the clone of the state
        if (cid === -1) {
            a[pid].parent = !a[pid].parent;
        } else {
            a[pid].child[cid] = !a[pid].child[cid];
        }

        this.setState({
            ... this.state,
            selected: a
        });
    }

    componentWillUpdate(nextProp, nextState) {
        console.log(JSON.stringify(nextState));
    }

    render() {
        return (
            <NestedListView
                data={data}
                getChildrenName={() => 'descendants'}
                onNodePressed={category => {
                }}
                renderNode={(item, level) => {
                    switch (level) {
                        case 1:
                            return (
                                <NestedRow level={level} style={{ marginLeft: -10 }}>
                                    <View
                                        style={[
                                            styles.node,
                                            {
                                                backgroundColor: colorLevels[level] || 'white',
                                                paddingLeft: (level + 1) * 30,
                                            },
                                        ]}>
                                        <Text>{item.name}</Text>
                                        <TouchableOpacity onPress={() => this.toggleChecked(item.parentId)}>
                                            {
                                                this.state.selected[item.parentId] ?
                                                    <Text>CHECKED</Text>
                                                    :
                                                    <Text>NOT CHECKED</Text>
                                            }

                                        </TouchableOpacity>
                                    </View>
                                </NestedRow>
                            );
                            break;
                        case 2:
                            console.log(item.parentId, item.childId);
                            return (
                                <NestedRow level={level} style={{ marginLeft: -10 }}>
                                    <View
                                        style={[
                                            styles.node,
                                            {
                                                backgroundColor: colorLevels[level] || 'white',
                                                paddingLeft: (level + 1) * 30,
                                            },
                                        ]}>
                                        <Text>{item.name}</Text>
                                        <TouchableOpacity onPress={() => this.toggleChecked(item.parentId, item.childId)}>
                                            {
                                                this.state.selected[item.parentId].child[item.childId] ?
                                                    <Text>CHECKED</Text>
                                                    :
                                                    <Text>NOT CHECKED</Text>
                                            }

                                        </TouchableOpacity>
                                    </View>
                                </NestedRow>
                            );
                            break;
                    }

                }}
            />
        )
    }
};

As you can see, when clicking on the TouchableOpacity to change the state of the selected node from true to false and false to true (basically toggling), the componentWillUpdate is shown to have updated the state (for example, clicking the first parent “CHECKED” will toggle the value), but the view itself is not rendering the updated value.

Thank you.

Edit: https://www.youtube.com/watch?v=Cpp1hRQrgR0&feature=youtu.be

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:10 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
fjmorantcommented, Jul 20, 2018

@ShaunLWM Published a new version with these changes, I close this issue

1reaction
fjmorantcommented, Jul 15, 2018

Hi @ShaunLWM ,

Worked already this issue, the problem is that you want to refresh NestedListView without changing any prop in the component.

In order to fix this problem I am going to create a new prop extraData (as it is done as well in FlatList) to update the list depending on external data, here you have a PR https://github.com/fjmorant/react-native-nested-listview/pull/91

You can see in this PR that I also I have added a new example.

Soon, I will release it because I think it is a common case to have an external state and the need to update a row.

Thanks

Read more comments on GitHub >

github_iconTop Results From Across the Web

Nested Components not updating their state - Stack Overflow
Whenever we encounter a change in the props that are stored in the state and the props coming from the parent, we update...
Read more >
[8.0.0+] Nested Rows, updating settings expands all parents ...
[8.0.0+] Nested Rows, updating settings expands all parents and not keeping the previous state ( was working in version 8+ ) #8838.
Read more >
Why is it so difficult to modify a deeply nested state in React?
There are two main ways to deal with the problem of updating a deeply nested state. First is flattening your state to avoid...
Read more >
Nested Rows table does not rerender - Handsontable Forum
Hello, I am using the React Wrapper for HOT. The data in my nested rows table is equal to the state of the...
Read more >
Hooks FAQ - React
However, we recommend to split state into multiple state variables based on which values tend to change together. For example, we could split...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found