1

I am creating an app with React/Redux, I have successfully managed to create an action/reducer to insert a record into my database - which is ForerunnerDB

My code so far looks like this:

PAGE

class Projects extends Component {
  componentWillMount() {
    this.props.FetchProjects();
  }

  renderProjects() {
    return this.props.projects.map( ( project ) => {
      return (
        <li key={ project._id } >
          <Link to={ `/pages/${project._id}` } >{ project.title } { project.timestamp.toString() }</Link>
        </li>
      );
    });
  }

  render() {
    return (
      <div className="projects container">
        <div className="projects">
          <ul>
            <li>
              <CreateNewProject />
            </li>
            { this.renderProjects() }
          </ul>
        </div>
      </div>
    );
  }
}

function mapStateToProps( state ) {
  return {
    projects: state.projects.all
  }
}

export default connect( mapStateToProps, actions )( Projects );

I am using the <CreateNewProject /> component to insert the record and the renderProjects() method to fetch the list of projects. The projects are rendered just fine if I refresh the page, but I cannot figure out to get the list to update at the point a record is inserted into the DB automatically.

Can anyone help point me in the right direction?

Many thanks in advance.

EDIT

PROJECTS actions

// Fetch existing projects
export function FetchProjects() {
  return ( dispatch ) => {
    // Load projects collection
    projectsCollection.load( ( err ) => {
      // if there are no errors
      if( !err ) {
        // Set up action payload
        const projects = projectsCollection.find();
        // Dispatch the action using the above
        dispatch({
          type: FETCH_PROJECTS,
          payload: projects
        });
      // If there's an error loading the projects collection
      } else {
        //Log the error
        console.log( `ERR! ${err}` );
      }
    });
  }
}
// Create new project
export function CreateProject( { projectName } ) {
  return ( dispatch ) => {
    // Load projects collection
    projectsCollection.load( ( err ) => {
      // If there are no errors
      if( !err ) {
        // Set up action payload
        // Insert record into projects collection
        const projectCreate = projectsCollection.insert({
          title: projectName,
          timestamp: fdb.make( new Date() )
        }, ( result ) => {
          // If insertion is successful
          if( result.inserted.length ) {
            // Save the projects collection (persisted to local storage)
            projectsCollection.save( ( err ) => {
              // If there are no errors
              if( !err ) {
                console.log( result.inserted[0] )
              } else {
                // Log the error
                console.log( `ERR! ${err}` );
              }
            });
          } else {
            // Log the failed insertion
            console.log( `ERR! ${result.failed}` );
          }
        });
        // Dispatch the action using the above
        dispatch({
          type: CREATE_PROJECT,
          payload: projectCreate
        });
      // If there's an error loading the projects collection
      } else {
        // Log the error
        console.log( `ERR! ${err}` );
      }
    });
  }
}

FETCH_PROJECTS reducer

// Import dependencies
import { FETCH_PROJECTS } from '../../actions/types';

// Set inital state
const INITIAL_STATE = { all: [] }

export default function( state = INITIAL_STATE, action ) {
  switch( action.type ) {
    case FETCH_PROJECTS:
      return { ...state, all: action.payload }
  }

  return state;
}

CREATE_PROJECTS reducer

import { CREATE_PROJECT } from '../../actions/types';

export default function( state = {}, action ) {
  switch( action.type ) {
    case CREATE_PROJECT:
      return { ...state, projects: action.payload }
  }

  return state;
}
2
  • looks like you should use one more time this.props.FetchProjects() to get data up to date. That's occurs because you are using props which dont trigger render method, instead of state Commented May 18, 2016 at 13:52
  • @TheReason where would I put that call is there an appropriate lifecycle method? Commented May 18, 2016 at 13:55

1 Answer 1

1

You should pass an action to CreateNewProject component. That way you can fire the action to insert a new record from the component. That action will then update the store via a reducer. Once the store is updated, it will trigger an update to the Projects component since it maps one of its props to the projects store.

EDIT -- additional code provided in question reveals more:

I noticed something which may be causing the issue. Inside PROJECTS actions, the function CreateProject has an issue with synchronicity. You attempted to create projectCreate and then pass that as the payload in your action. The problem is that projectsCollection.insert() is an asynchronous function (indicated by the callback). What this means is the dispatch() call has an undefined value for projectCreate.

I suggest putting the dispatch() call inside the last callback, projectsCollection.save():

      projectsCollection.save( ( err ) => {
          // If there are no errors
          if( !err ) {
            console.log( result.inserted[0] )
            // dispatch the successful result
            dispatch({
              type: CREATE_PROJECT,
              payload: result.inserted[0]
            });
          } 
          ...
       }
Sign up to request clarification or add additional context in comments.

3 Comments

thats exactly what I have done. I will edit my question above to show the actions/reducers
thats make sense. I have tried what you suggest but unfortunately I haven't managed to get it working. Am I referring to state correctly in the reducers? Might be a daft suggestion but this is my first project using React Redux.
I've never used the approach you're using, so I cannot comment if its good or bad. I use ImmutableJS for my reducers to ensure they are pure. Typically I have only one reducer per store, and I handle all the actions supported by that reducer in a switch statement. I would suggest using Object.assign() to merge new data with the current state; as that will return a new object. Perhaps it would be beneficial for you to read redux.js.org/docs/basics/Reducers.html

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.