Using props to initially set state

I've been doing some research tonight surrounding the topic of using props to set the initial state of a component, and I've come across people arguing both sides. My question, therefore has two parts.

1) Is what I am doing considered the anti-pattern? From what I can tell it is not -- according to this article If so, what specifically is wrong with it?

2) Is there another way I could re-write this logic without using props to set the state?

Parent Component:

class App extends Component {

  constructor(props){
    super(props);
    this.state ={
      todos: []
    }
  }

  componentDidMount() {
    axios.get('https://jsonplaceholder.typicode.com/todos')
    .then(response => {
      this.setState({ todos: response.data })
    });
  }

  render() {
    if(!this.state.todos){
      return <div>Loading...</div>
    }
    return (
        <div className="container">
          <div className="row">
            {
              this.state.todos.map((todo, i) => {
                return (
                  <Todo todo={todo} key={i}/>
                )
              })
            }
          </div>
        </div>
    );
  }
}

Child Component

class Todo extends Component{

  constructor(props) {
    super(props);
    var { title, completed, userId } = this.props.todo;
    this.state = { title, completed, userId }
  }
  changeCompletion = () => {
    this.setState({completed: !this.state.completed})
  }

  render() {
    return(
      <div className="col-md-4 col-sm-6">
        <div className={"card card-inverse text-center " + (this.state.completed ? 'card-success' : 'card-danger')}>
          <div className="card-block">
            <blockquote className="card-blockquote">
              <p>{ this.state.title }</p>
            </blockquote>
            <button onClick={this.changeCompletion} className={"btn btn-sm " + (this.state.completed ? 'btn-danger' : 'btn-success')}>{ this.state.completed ? 'incomplete' : 'complete'} </button>
          </div>
        </div>
      </div>
    )
  }
}

1. Is what I am doing considered the anti-pattern? - Maybe, YES

The problem is the constructor of your child component only runs once across multiple renders. If you use setState() in your child component to re-render the constructor won't run again thus the props and the state are out of sync which is the "multiple sources of truth" problem the article mention.

If you re-render you parent component (either through state change, props change, or this.forceUpdate()), you child component's constructor won't re-execute. That is, React does this to improve performance internally, you can use console.log() to investigate the component's life-cycles.

Usually, if I bump into your situation, I will add a life-cycle method called ComponentWillReceiveProps(nextProps) and use the nextProps there to re-initiate the state. Although it is not the perfect solution because other developers may modify the props in the component and we are back at the "multiple sources of truth" problem. You need to tell or educate other developers in your project that they are not allowed to modify props directly or indirectly in the component but even though, they may forget sometimes. But at least adding the life-cycle method does improve the situation.

2. Is there another way I could re-write this logic without using props to set the state?

You can try this approach: Basically, you expose a callback in child component's props and in the parent component, you execute it to trigger re-render of the parent component which in turn trigger re-render of all child components which is what we want.

And keep in mind that, when React re-renders all child components, it does not destroy then re-create all of them thus their constructor won't re-execute. Only their life-cycle method ComponentWillReceiveProps(nextProps) will be executed.

Parent Component:

<Todo todo={todo} key={i} onChangeCompletionCallback={() => {
    let clonedState = Object.assign({}, this.state);
    clonedState.todos[i].completed = !clonedState.todos[i].completed;
    this.setState(clonedState);
}}/>    

Child Component

changeCompletion = () => {
    this.props.onChangeCompletionCallback();
}