Try to call function inside controller in react component - javascript

I am trying to get use to the base code of webtorrent desktop, here you can check the code of my branch:
https://github.com/refreex/webtorrent-desktop
It uses Node.js and Electron
The problem I am facing is I create a new controller called playlists-controller.js and there is a function called getAllPlaylists that I need to consume within a React component called playlists-list.js
I am trying to use the same concepts that were used before but I don't understand how can i call that function from my controller inside the react's component.
There is a file called main.js where here are listed all the functions that the controllers have like this one:
//Playlists
'createPlaylist': (name) => controllers.playlists().createPlaylist(name),
'addAlbumToPlaylist': (infoHash, files) => controllers.playlists().addAlbumToPlaylist(infoHash, files),
'addSongToPlaylist': (infoHash, file) => controllers.playlists().addSongToPlaylist(infoHash, file),
'getAllPlaylists': () => controllers.playlists().getAllPlaylists(),
Along the app there are a lots of calls using a dispatcher but also I think is mostly used for events but I am not sure.
So basically in the page playlists-list.js I need to call the function getAllPlaylists that is in playlists-controller.js
What is a good approach to do that?
Thanks in advance.

This can be done in two ways. One, passing the function as props to that component or we can export the getAllPlaylist method and use it by importing into the playlists-lists component. I hope this will help you solve your issue.
Method 1:
class PlaylistController extends React.Component {
getAllPlaylist = () => {
alert('Do Something Here As Per Your Requirement!')
}
render () {
return (
<container>
<PlaylistList sendFunction={this.getAllPlaylist} />
</container>
)
}
}
class PlaylistList extends React.Component {
render () {
return (
<div>
<button onClick={this.props.sendFunction}>Click Here To Call Playlist-list Function</button>
</div>
)
}
}
Method 2:
class PlaylistController extends React.Component {
export const getAllPlaylist = ()=>{
//do something as per the requirement
}
}
import {getAllPlaylist} from './playlistController'
class PlaylistList extends React.Component {
handleClick = () => {
getAllPlaylist();
}
render () {
return (
<div>
<button onClick={this.handleClick}>Click Here To Call Playlist-list Function</button>
</div>
)
}
}

Related

correct coding structure in React.js?

I'm new to react and I'm still using the life cycle methods, so my question is since componentDidMount() acts like a constructor I'm planning to initialize everything there:
render() {
return (
<div className="done-container" style={this.style().taskContainer}>
<span style={this.style().title}>Done</span>
{
this.props.done.map((d) => (
<div className={`done ${this.state.isActive ? 'active' : ''}`} id={this.props.done.id}
onClick={(e) => {
this.props.setTaskID(d.id);
this.setToActive(e); //3.Call <-----
this.props.arrowStyleToDone();
}}>
</div>
))
}
</div>
)
}
setToActive //1.Declare <----
componentDidMount() {
//2.Initialize <-----
this.setToActive = (e) => {
if(!e.target.classList.contains('active')) {
e.currentTarget.classList.add('active');
e.currentTarget.classList.add('border-done')
this.props.closeAllTasks();
this.props.closeAllDoing();
} else {
e.currentTarget.classList.remove('active');
e.currentTarget.classList.remove('border-done')
this.props.disableArrowButton();
}
}
}
}
My idea is that if I declare everything inside the class which looks very ugly in my opinion, but then initializing everything on componentDidMount() instead of putting everything inside the render(), my web app will be faster because it won't need to declare and initialize everything every render.
Is this correct? and should I put the declaring and initialization on top of render()? but the componenDidMount() is called after the initial render.
and should I put the declaring and initialization on top of render()
Typically the render function is put at the end of your class
but then initializing everything on componentDidMount() my web app will be faster because it won't need to declare and initialize everything every render.
I don't think you understand how React/classes work... If you do
class MyComponent extends React.Component {
someFunc() {
...
}
render() {
...
}
}
the someFunc function isn't re-declared every render. If you are worried about this binding issues, you can just do
class MyComponent extends React.Component {
constructor() {
this.someFunc = this.someFunc.bind(this);
}
someFunc() {
...
}
render() {
...
}
}

React onClick, Cannot read property 'bind' of undefined

I'm trying to run a onclick function in react
My button:
<button onClick={this.logOut.bind(this)}>LogOut</button>
My function
function logOut(){
Auth.signOut()
.then(data => console.log(logout)
.catch(err => console.log(err));
}
but the an error comes back Cannot read property 'bind' of undefined
Firstly, never bind in your render method. bind returns a new method each time you call it, which means that react cant optimise your render method. React looks at the props of components to see if anything has changed, and with functions, it compares equality by object reference. Since your function will be a new function each time, react will think things are changing.
Secondly, you can use an arrow function in your component to avoid the need for bind all together.
Here are two ways you can write this differently, first with bind:
class MyComponent extends Component {
constructor() {
this.logOut = this.logOut.bind(this);
}
function logOut() {
//...
}
function render() {
return <button onClick={this.logOut}>LogOut</button>
}
}
Secondly with an arrow function:
class MyComponent extends Component {
logOut = () => {
//...
}
function render() {
return <button onClick={this.logOut}>LogOut</button>
}
}
Would be helpful if you can please give more details .
Just tried an example in codepen and I see it working fine.
https://codepen.io/anon/pen/qKBdaB?editors=0011
class Toggle extends React.Component {
handleClick() {
console.log('Hello')
}
render() {
return (
<button onClick={this.handleClick.bind(this)}>
SayHello
</button>
);
}
}
ReactDOM.render(
<Toggle />,
document.getElementById('root')
);

React - Setting component state using a function outside of state, is it wrong?

Is it wrong to use setState in a function outside of the React component?
Example:
// myFunction.js
function myFunction() {
...
this.setState({ ... })
}
// App.js
import myFunction from './myFunction
class App extends Component {
constructor() {
super()
this.myFunction = myFunction.bind(this)
}
...
}
I'm not sure the way you're binding will actually work. You could do something like:
export const getName = (klass) => {
klass.setState({ name: 'Colin'})
}
then
class App extends Component {
state = {
name: 'React'
};
handleClick = () => {
getName(this);
}
render() {
return (
<div>
<p>{this.state.name}</p>
<button onClick={this.handleClick}>change name</button>
</div>
);
}
}
Working example here.
So the only reasons to do this is if you are reducing repeated code, e.g. two components use the same logic before calling this.setState, or if you want to make testing easier by having a separate pure function to test. For this reason I recommend not calling this.setState in your outside function, but rather returning the object you need so it can you can call this.setState on it.
function calculateSomeState(data) {
// ...
return { updated: data };
}
class MyComponent extends React.Component {
constructor(props) {
super(props)
this.state = calculateSomeState(props.data);
}
handleChange = (e) => {
const value = e.target.value;
this.setState(calculateSomeState({ ...props.data, value }));
}
}
It looks like a bug waiting to happen... If you want to use an external function to set state, you can use the alternative syntax provided by React:
this.setState((prevState, props) => {
return updatedState; //can be a partial state, like in the regular setState
});
That callback can easily be extracted to an external function and it's guaranteed to work
It is not wrong, the function is never called outside the component. This is a mix-in technique. bind isn't needed, as long as the function isn't used as a callback. In this case myFunction is same among all instances, a more efficient way would be:
class App extends Component {}
App.prototype.myFunction = myFunction;

Call class method of default import in react

I'm wondering whether its possible to call a method on a component that I import from another file. Basically, my situation is that I have two react classes. One of them is a Sudoku puzzle, which I call Game, and which includes the updateArray() method:
class Game extends React.Component {
constructor(props) {
super(props);
this.state = {arr: [[5,0,4,9,0,0,0,0,2],
[9,0,0,0,0,2,8,0,0],
[0,0,6,7,0,0,0,0,9],
[0,0,5,0,0,6,0,0,3],
[3,0,0,0,7,0,0,0,1],
[4,0,0,1,0,0,9,0,0],
[2,0,0,0,0,9,7,0,0],
[0,0,8,4,0,0,0,0,6],
[6,0,0,0,0,3,4,0,8]]};
this.handleSubmit = this.handleSubmit.bind(this);
this.updateArray = this.updateArray.bind(this);
}
componentWillReceiveProps(nextProps) {
if(nextProps.arr != this.props.arr){
this.setState({arr: nextProps.value });
}
}
updateArray(str_arr) {
this.setState({arr: str_arr});
}
handleSubmit(event) {
...
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<div className = "game">
<div className = "game-board">
<Board value = {this.state.arr} />
</div>
<div className = "game-info">
<div></div>
</div>
</div>
<input type="submit" value="Submit" />
</form>
);
}
}
export default Game;
And then I have a second class that gets a image of a sudoku puzzle and makes a corresponding 9x9 array using computer vision methods. I then try to send the array back to Game using its updateArray function:
import Game from './Sudoku';
export default class ImageInput extends React.Component {
constructor(props) {
super(props);
this.state = {
uploadedFile: ''
};
}
onImageDrop(files) {
this.setState({uploadedFile: files[0]});
this.handleImageUpload(files[0]);
}
handleImageUpload(file) {
var upload = request.post('/')
.field('file', file)
upload.end((err, response) => {
if (err) {
console.error(err);
}
else {
console.log(response);
console.log(Game);
//ERROR HAPPENING HERE
Game.updateArray(response.text);
}
});
}
render() {
return (
<div>
<Dropzone
multiple = {false}
accept = "image/jpg, image/png"
onDrop={this.onImageDrop.bind(this)}>
<p>Drop an image or click to select file to upload</p>
</Dropzone>
);
}
}
However, when I try to send the array to Game's method, I get a Uncaught TypeError:
Uncaught TypeError: _Sudoku2.default.updateArray is not a function
at eval (image_input.js?8ad4:43)
at Request.callback (client.js?8e7e:609)
at Request.eval (client.js?8e7e:436)
at Request.Emitter.emit (index.js?5abe:133)
at XMLHttpRequest.xhr.onreadystatechange (client.js?8e7e:703)
I want the updateArray() method to update the Game from a separate file, which will then cause the Game to re-render. Is this possible? I've spent a lot of time reading documentation, and it seems as though what I'm suggesting is not the typical workflow of react. Is it dangerous, and if so, can someone explain why?
Also, both classes are rendered in a separate file that looks like this:
import Game from './Sudoku';
import ImageUpload from './image_input';
document.addEventListener('DOMContentLoaded', function() {
ReactDOM.render(
React.createElement(ImageUpload),
document.getElementById('image-upload'),
);
ReactDOM.render(
React.createElement(Game),
document.getElementById('sudoku_game'),
);
});
First of all, in your separate file (the one rendering both Game and ImageInput components):
Make it render only one component. This could have a original name like App for instance. Like this:
import App from './App';
document.addEventListener('DOMContentLoaded', function() {
ReactDOM.render(
React.createElement(App),
document.getElementById('root'),
);
});
You would only have to change the imports and name of the root element as needed of course.
Then, for the App component:
import React from 'react';
import Game from './Sudoku';
import ImageUpload from './image_input';
class App extends React.Component {
constructor() {
super();
this.state = {
sudokuArray = [];
}
}
updateArray(newArray) {
this.setState({sudokuArray: newArray})
}
render() {
<div>
<Game sudokuArray={this.state.sudokuArray} />
<ImageUpload updateArray={this.updateArray.bind(this)} />
</div>
}
}
export default App;
And inside your ImageInput component you would call the update method like:
this.props.updateArray(response.text).
Also, inside your Game component, change the render function, specifically the part with the Board component to: <Board value = {this.props.sudokuArray} />.
This is a rather common situation when you are learning React. You find yourself trying to pass some prop or run some method inside a component that is not "below" the component you are currently working with. In these cases, maybe the prop you want to pass or the method you want to run should belong to a parent component. Which is what I suggested with my answer. You could also make Game as a child of ImageInput or vice-versa.

Calling a function in React

I'm a beginner in React, and I'm a little confused about calling a function in React.
I saw the following ways and I don't know when to use each and which one.
handleAddTodo ={this.handleAddTodo}
handleAddTodo ={this.handleAddTodo()}
handleAddTodo ={handleAddTodo}
handleAddTodo ={this.handleAddTodo}
handleAddTodo ={handleAddTodo()}
Are these interchangeable? Could I do that to handle an event, the same way to call a function?
Are these interchangeable?
Short answer: No.
Let's take a look at the different snippets you've posted:
someFunction() vs someFunction
With the former syntax, you are actually invoking that function. The latter is just a reference to that function. So when do we use which?
You would use someFunction() when you want that function invoked and its result returned immediately. In React, this is typically seen when you split parts of your JSX code to a separate function; either for reasons of readability or reusability. For example:
render() {
myFunction() {
return <p>Foo Bar</p>;
}
return (
<div>
{myFunction()}
</div>
);
}
You would use someFunction when you want only to pass the reference to that function to something else. In React, this is usually an event handler that is passed down to another child-component via props so that that component can call the event handler when it needs to. For example:
class myApp extends React.Component {
doSomething() {
console.log("button clicked!");
}
render() {
return (
<div>
<Button someFunction={this.doSomething} />
</div>
);
}
}
class Button extends React.Component {
render() {
return (
<button onClick={this.props.someFunction}>Click me</button>
);
}
}
someFunction() vs this.someFunction()
This has to do with the context of the function. Basically, "where is this function?". Is part of the current Component, then use this.someFunction(), is it part of the parent Component passed in as props, then use this.props.someFunction(). Is it a function inside the current method, then just use someFunction().
Obviously, there's a lot more to it than that, but it's the best basic summary I can give.
For a better understanding, have a read here. It is a great guide to how the this keyword works in Javascript and in React in particular.
If you want to call a function options 2 and with some assumptions 5 should work.
If you want to actually pass a function as a property to some child component so that it could call it later (say to notify your root element on some event) then option 1 (with prebind) and 3 (with defining a variable const {handleAddTodo} = this and prebind :) ) should work
// this works if handleAddTodo was prebinded or doesn't use this
handleAddTodo ={this.handleAddTodo}
// this probably wont work unless handleAddTodo is higher order function that returns another function
handleAddTodo ={this.handleAddTodo()}
// This wont work unless you have a var/let/const that is referencing a function
handleAddTodo ={handleAddTodo}
// Same as 1
handleAddTodo ={this.handleAddTodo}
// 3 and 2 combined
handleAddTodo ={handleAddTodo()}
To call the function you have to add ()
{this.handleAddTodo()}
About handling events - Handling#Events
Arrow Functions - Functions#ArrowFunctions
In ES6 you can use normal function or Arrow Function:
Function1 (Normal Function)
functionA(){
//Something here
}
Then should call this.functionA()
Function2 (ArrowFunction)
functionA = () => {
//SomeThing Here
}
Then should call this.functionA
*Function3 (Eg: in a const of React) *
const A = (functionTest) =>{
return (
<div>{functionTest}</div>
);
}
functionTest is mapStateToProps in React :)
I hope it is helpful for you :)
this is correct -> handleAddTodo ={this.handleAddTodo}
When function passing to child component you have to bind your function like this handleAddTodo ={this.handleAddTodo.bind(this)}. below code help out your doubt.
Simple Example
import React from 'react';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: 'Initial data...'
}
this.updateState = this.updateState.bind(this);
};
updateState() {
this.setState({data: 'Data updated...'})
}
render() {
return (
<div>
<button onClick = {this.updateState}>CLICK</button>
<h4>{this.state.data}</h4>
</div>
);
}
}
export default App;
Child Events
import React from 'react';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: 'Initial data...'
}
this.updateState = this.updateState.bind(this);
};
updateState() {
this.setState({data: 'Data updated from the child component...'})
}
render() {
return (
<div>
<Content myDataProp = {this.state.data}
updateStateProp = {this.updateState}></Content>
</div>
);
}
}
class Content extends React.Component {
render() {
return (
<div>
<button onClick = {this.props.updateStateProp.bind(this)}>CLICK</button>
<h3>{this.props.myDataProp}</h3>
</div>
);
}
}
export default App;
Refer here
You can trigger events with this.props.someProps(). Check the following sample.
import React, { Component } from 'react';
class AddToDo extends Component {
render() {
return (
<button onClick={ev => this.props.handleAddToDo(ev, 'hello')}>
{this.props.title}
</button>
)
}
}
class Todos extends Component {
handleAddToDo(ev, someVal) {
// do something
}
render() {
return (
<AddToDo title="Add" handleAddToDo={(ev, someVal) => this.handleAddToDo(ev, someVal)} />
)
}
}
export default Todos;

Categories

Resources