dynamic image for autocomplete / components - javascript

I am trying to make a crypto react native app, I am trying to have icons to match with an autocomplete. So it would work very similar to the coinmarketcap search, where you can type a coin symbol and you will see the corresponding coin with its icon.
I think there could be a few ways to do this and I think this would be a good place for discussion on what is the best way.
For starters, I created a script that would take all the icons in a directory (SVG or PNG), and create a json that would have the symbol as the value and the key will be a reference to the icon.
With this method there are a few problems I have encountered. The solutions have been covered in this post.
React Native - Dynamic Image Source.
However, it has been hard for me to find a good solution to either
A. Encode all the image in a directory into a base64encoded string and put it into a json
B. Create an array on the React Native end which will have the require('path-to-image')
Relevant code examples are in the post so i dont want to repeat it, but I guess I would just like to know which one is the best practice. I think that doing it as a array of modules would be best. But I am not sure have to dynamically create something like that.
example of the dictionary I created is something like this:
Given a JSON object like this how would you extend it so it would become
const image = {
key1: 'path/to/key/one.png'
key2: 'path/to/key/two.png'
}
To
{
key1: require('path/to/key/one.png'),
key2: require('path/to/key/two.png')
}
you would it to fit into a react native component like so
<Image
source={ (images[symbol])}
/>

You have a couple of options, and I think you nailed the best one in your case (tested in React Native 0.50.3):
import {Image} from 'react-native'
export default (props) => <Image source={icons[props.currency]} />
const icons = {
bitcoin: require('../path/to/bitcoin.png'),
ethereum: require('../path/to/ethereum.png'),
...
}
Lol that's basically exactly what you already wrote in your question. I've also gotten away with storing a bunch of require(...) statements in an array and pulled by index, e.g:
import {Image} from 'react-native'
export default (props) => <Image source={icons[props.index]} />
const icons = [
bitcoin: require('../path/to/bitcoin.png'),
ethereum: require('../path/to/ethereum.png'),
...
]
This approach is really only useful if you don't know the key to identify your target reference by (e.g if you wanted to cycle through a bunch of images randomly). For the described use case I'd go with key lookup.

Related

Appending JSX in React Native

I'm searching for a way to add a JSX element programmatically in React Native. Not conditionally.
It needs to be independent function, so far I couldn't find anything about this. Let me give you code example;
const appendJSX = () => {
const jsx = <Text> Hello! </Text>
append(jsx) // <---- can we do something like this?
}
let's say I call this function with useEffect and it should add whatever jsx I have inside the function. Up until this point I always see things like pushing inside of an array or something like that.
UPDATE
Equivalent behaviour that works on web;
useEffect(() => {
const div = document.createElement("div");
div.innerText = "appended div"
document.body.append(div)
}, [])
As you can see we don't have to touch any JSX in application. Reaching document.body and appending whatever we want is possible in React Web. But how can we achieve this in React Native?
Not quite sure what you want to do, but as for to add a JSX manually. Here's the answer.
JSX is already part of the language in most of the cases.
const a = <Text />
export default a
Will translates into:
const a = createElement(Text, null, null)
export default a
Therefore in most of common cases, if you continue using React somewhere else, then the variable a holds a React element without any compilation error.
You might wonder what a actually really holds, it's an object:
const a = {
$$typeof: Symbol(ReactElement),
props: null,
type: Text
}
So you can see the only dependencies in above piece is Text and the ReactElement Symbol. As long as you can resolve them, you are good to export this to anywhere. The latter is normally taken care by Babel.
NOTE:
There's a difference between Text and <Text />. If you just want to export a Text which is a function component, there'll tutorial online, also you can dig into any third party library, because essentially that's what they do, export Text so other people can use it.

Is it a good idea to use React.Context to inject UI-Components?

I plan to build a react component library. The react components are UI-Components but should only implement a specific logic. I want the user to be able to define a set of atoms (basic react components) that are used to compose the actual components. My main goal is to make the library independent of a specific UI-Component-Library like MaterialUI, ChakraUI, etc.
My idea was to use a React.Context to inject the components like this:
// Button Atom
const Button: FC = ({ children }) => (<button>{children}</button>)
const atoms = { button: Button }
const AtomContext = createContext(atoms);
// "higher" component
const HigherComponent: FC = () => {
const atoms = useContext(AtomContext)
// Logic ...
return (
<atoms.button>click me</atoms.button>
)
}
export default function App() {
return (
<AtomContext.Provider value={atoms}>
<HigherComponent />
</AtomContext.Provider>
);
}
This solves my problem. But I'm not sure if it is a good idea. Are there better ways to inject UI-dependencies? What may be problems with my approach?
This is a question that can result in multiple answers based on personal experience.
But overall the idea to pass component trough context is a bit of misuse of that concept.
Also it does not bring much benefit from making a standalone library that can be imported via package.json or making a folder with components and importing them.
If you need to pass some specific things to your components you can have a custom provider as you did there, but as far as the component themselves, there is no common sense to use context.
If you end goal is to shorten the list of imports of component with custom context hook and just getting them like that, I think that is a bad tradeoff overall.
I just read this article about using react context for dependency injection. The authors opinion is, that react context for injecting non-react dependencies into components is good practice. However, I'm not sure if that applies to injecting a specific set of react components. Since, react components are nothing more than functions I think it should be alright to use reacts context for that.

Will JSX conditional rendering out of an object code split?

Will conditional rendering out of an object code split and lazy load as expected? Here's a short example of what I'm talking about.
const Component1 = lazy(() => import('some path'));
const Component2 = lazy(() => import('some path'));
const Component3 = lazy(() => import('some path'));
render () {
const { selectionIndex } = this.state;
<Suspense fallback={<div>Loading...</div>}>
{{
one: <Component1 />,
two: <Component2 />,
three: <Component3 />,
}[selectionIndex]}
</Suspense>
}
I want to know whether all three components will load on render, or just the one selected by selectionIndex. I'm trying to use this to conditionally select something to display based on a menu set by state, but I don't want to load everything at once.
They will not get rendered all at once. You can experiment by yourself, put console.log inside components is an easy way to find out.
React for web consists of two libs, "react" and "react-dom". "react" is in charge of encapsulating your logic intention into declarative data structures, while "react-dom" consumes these data structures and handles the actual "rendering" part of job.
The JSX element creation syntax <Component {…props} /> translates to plain JS as an API call to React.createElement(Component, props). The return value of this API call is actually just a plain object of certain shape that roughly looks like:
{
type: Component,
props: props
}
This is the aforementioned "declarative data structure". You can inspect it in console.
As you can see, calling React.createElement just return such data structure, it will not directly call the .render() method or functional component’s function body. The data structure is submitted to "react-dom" lib to be eventually "rendered".
So your example code just create those data structures, but the related component will not be rendered.
seems like its conditionally loaded based on selectionIndex. all the other components are not loaded at once.
P.S.: if you ever feel like which will get load first, just put a console log in that component and debug easily
conditionally load demo link - if you open this, the components are being loaded initially based on selectionIndex value being "one".
I'm not going to go into too much technical detail, because I feel like #hackape already provided you with a great answer as to why, point of my answer is just to explain how (to check it)
In general, I'd recommend you to download download the React Developer Tools
chrome link
firefox link
and then you can check which components are being rendered if you open the components tab inside your developer console. Here's a sandboxed example, best way to find out is to test it yourself afterall :-)
As you can see in the developer tools (bottom right), only the currently set element is being rendered

Input value into react-native svg uri

Hello I am trying to input a value into an SVG URI in React-Native as follows:
source={require('../tasks/images/' + {task.image} + '.png')}
I am currently iterating through an array of objects and outputting the svgs for each, so I want to do it this way but the syntax isnt accepted.
Any help or advice is welcome!
Because there is no way to make the string passed to require dynamically, you could have an image collection file that references every image you would need, for example:
Create a file ImageCollection.js with the following:
export default imageCollection={
"1": require("./image1.png"),
"2": require("./image2.png"),
"3": require("./image3.png"),
"4": require("./image4.png")
}
Then import it into your file where you need to require your images and do something like this:
import Images from './ImageCollection.js';
class YourComponent extends Component {
renderItem = ({item}) => (
<View>
<Text>Image: {item}</Text>
<Image source={Images[item]}/>
</View>
);
render () {
const data = ["1","2","3","4","5"]
return (
<FlatList data={data} renderItem={this.renderItem}/>
)
}
}
export default YourComponent;
But if you really need to pass dynamic image sources then you could use a package like react-native-image-progress which lets you pass a variable as an image source, I wouldn't recommend this approach unless if there is absolutely no other way for you to solve this problem.
Here, you cannot pass dynamic images path which is available locally as your assests.
Moreover if you have image URI which is coming from the server then you can just provide here and it will work like a charm. But for image Path which is present locally you have to provide actual path. More you can read here.
However, what you can do just provide nested if else for the path based on the conditions, but then please note, you have to provide the full path as well.
Example :-
source={this.state.data===1?require('../tasks/images/image1.png'):this.state.data===2?require('../tasks/images/image2.png'):require('../tasks/images/image3.png')}
Thanks....Hope it helps :)

How to combine emojione with markdown in React?

Right now I am trying to parse some text with both react-emojify and react-markdown. I would like to combine somehow the functionality of both utilities.
Problem is (if I understand correctly) that both convert string into React DOM. When I run emojify on content the result cannot be passed into <ReactMarkdown source={result} /> and vice versa.
I was thinking about doing sth like serializing React DOM into HTML and allowing some tags in the other parser, but both have rather limited options when it comes to making them compatible (e.g. emojify spits emoticons as spans which cannot be allowed in ReactMarkdown).
Have anyone else tried that? Is there some way (even by changing libraries) that could help me achieve this?
I managed to make things work by replacing react-emojify with emojione:
import emojione from 'emojione';
import React from 'react';
import ReactMarkdown from 'react-markdown';
class ExampleComponent extends React.Component {
render() {
const content = this.props.content;
const emojified = emojione.shortnameToImage(content);
return (
<ReactMarkdown source={emojified} />
);
}
}
Later on I only had to tweak how emojis are shown by changing .emojione class properties in CSS (as opposed to passing option object into react-emojify function).

Categories

Resources