The newer javascript specs include many syntax shorthands. The following are all equivalent, defining a function that creates an object with a specified title and the option to define a non-default list.
Standard es5 function.
function createTodo(title, list) {
return {
title: title,
list: list || 'default',
status: 'incomplete'
};
}
Incorporating arrow function.
const createTodo = (title, list) => {
return {
title: title,
list: list || 'default',
status: 'incomplete'
};
};
Incorporating arrow function shorthand for returning an object
const createTodo = (title, list) => ({
title: title,
list: list || 'default',
status: 'incomplete'
});
Incorporating a default argument (behaves just like Python's!)
const createTodo = (title, list = 'default') => ({
title: title,
list: list,
status: 'incomplete'
});
Incorporating "object value shorthand", where the key name matches variable name
const createTodo = (title, list = 'default') => ({
title,
list,
status: 'incomplete'
});
All these syntax shorthands combined with Flow typing can result in code that looks far from standard JavaScript.
handleActions
comes from the
redux-actions library. It takes
a handler Object and a default state, where the Object maps an action type to a
function to run if the action is that specified type. For an easier mental model
of how this works, see these
redux docs for how a plain
reducer function can be written without redux-actions
.
Two syntaxes for the same thing: responding to asynchronous tasks. For example,
if an API util fetchData
exists, it would return a promise to which you can
chain or await on. Here’s how you could do it using the different syntaxes.
function getRelevantData() {
return dispatch => {
dispatch(requestData());
APIUtils.fetchData().then(response => {
console.log(response);
dispatch(receiveData(response));
});
console.log('action evaluated');
};
}
// Would print 'action evaluated', and later print response
function getRelevantData() {
return async dispatch => {
dispatch(requestData());
const response = await APIUtils.fetchData();
console.log(response);
dispatch(receiveData(response));
console.log('action evaluated');
};
}
// Would print response, followed by 'action evaluated'
Essentially, choose whichever seems more readable for the situation.
Modern frontend development has a bias towards functional programming. Why?
React and Redux require it, as React uses changes in object references to
trigger a re-render. For example, consider updating an isLoading
field in a
reducer’s state. Setting state.isLoading = true
would maintain the same object
reference and React wouldn't know to trigger a re-render. To fix this, we
instead return a new object like:
[Actions.requestData]: (state) => {
return {
...state, // carry over all other fields into this new object
isLoading: true // overwrite the field we want to change
}
}
CSS changes can only be manually verified.
Javascript tests live in a __tests__
directory immediately beside the files
they’re testing. Testing a util function or reducer can be done with a jest unit
test. Run yarn run test
to verify
describe('newUtil', () => {
it('returns one!', () => {
expect(newUtil()).toBe(1);
});
});
Changes to a component will be reflected in any snapshot tests. Run
yarn run test -u
to update an existing snapshot.
describe('SomeComponent', () => {
it('matches snapshot', () => {
const component = <SomeComponent />;
expect(renderer.create(component).toJSON()).toMatchSnapshot();
});
});
Our code gets autoformatted by Prettier, and additional issues get flagged by
eslint. You will not be able to commit code that has linting errors. It's
recommended that you set up Prettier in your editor along with enabling format
on save ( IDE extensions here). You
can verify beforehand by running yarn run lint
.
- A cartoon intro to Redux
- Redux docs include a fleshed out Example showing everything you’d need to know
- Want to play with React without worrying about setup or finding a spot in our codebase? Play around on CodeSandbox