-
Notifications
You must be signed in to change notification settings - Fork 2
Writing React components guide
Is your component smart or dumb? If your component has the ability to alter state, it is a smart component. If not, skip to Storybooking.
How does your component affect state? Think of a good function name that follows the verbNoun pattern. We are using Redux which uses actions and reducers, so the first step is to create the action type. This is simply a string description of the action which we will save as a variable in another module to avoid Magic String Disease. In this example, we are going to create a new task so our action will be called ADD_TASK. Create this action type in app/action_types/index.js.
export const ADD_TASK = 'ADD_TASK';
Go to app/action_creators/index.js and add the action type to the list of imports from action_types at the top of the file.
import { ADD_TASK } from '../action_types';
Then write your addTask function. Think about the parameters your function needs to take and their data types. In this example, our tasks only have a title as a string. you do not need to pass all data as a parameter. For example, here I have included a timestamped ID using the universally unique identifier (UUID) node module.
export const addTask = (title: string): Object =>
({
type: ADD_TASK,
title,
id: uuid.v1(),
});
Go to app/reducers/ and create a new reducer module for your entity if it doesn't already exist. At the moment, there are no task reducers so we are going to make a new file called tasks.js in the app/reducers/ directory. Add your action type to the list of imports at the top of the file.
import { ADD_TASK } from '../action_types';
Write the reducer function which describes how you would like to alter state. The following function takes the existing state, adds our title and id and returns the new state.
const addTask = (state, { title, id }) =>
[...state, { title, id }];
Then export a handler function for this entity's reducers. At the moment we don't have multiple actions per entity but use a switch statement all the same. As a default (i.e. if the action type doesn't exist), just return state (as if nothing happened).
const tasks = (state, action) => {
switch (action.type) {
case ADD_TASK:
return addTask(state, action);
default:
return state;
But I thought we were making components? Yes but all of our logic will be done by the containers which hold these components. The components themselves are dumb. Go to app/containers/ and create a new module for your container. Import react, redux, your dumb component and your task handler at the top of the file:
import React from 'react';
import { connect } from 'react-redux';
import { tasks } from '../reducers/tasks';
import NewTaskForm from '../components/new_task_form';
Open a connection to state with redux:
const connector = connect();
Create a function with the same name (but fully capitalised) which takes a dispatch object. This is reduxy stuff.
const AddTask = connector(({ dispatch }) => {
//Component goes in here
});
And inside this function write a function that you want to execute when the form is submitted. In this case we want to call addTask with the 'value' of the title field in our dumb component. Then export this this function.
const onSubmit = value => dispatch(addTask(value));
return (
<NewTaskForm
onSubmit={onSubmit}
value=""
/>
);
module.exports = AddTodo;
Congratulations you made a smart component!
Let's check out how it looks!
Go to the stories directory. Create a new file. This is where you choose which stories (scenarios) you would like to at.
storiesOf('NewTaskForm', module)
.add('simple', () =>
<NewTaskForm />
);
Go to the .storybook directory and update the loadStories function with your story file:
const loadStories = () => {
require('../stories/new_task_form');
Now run storybook and have a play with your component.
$ npm run storybook