I'm currently going through some tutorial about React Design Patterns, subject: Custom Hooks.
While the concept feels awesome and seems familiar to me, the solution below provided by the tutor made me question how to deal with different data sources.
Is there something like the above mentioned DAO Factory Pattern, you can find in Frameworks like J2E?
Or how is the common approach to handle this challenges in React to make the code maintainable?
My first intension woulda be throwing the stuff into a Factory Component and having implementations for the specific providers, basically like it is shown in the two other Code snippets bewlow.
Is this the regular wayt to do it?
Any help, tips, additional sources to learn this would be highly appreciated.
Here's the solution, with the both possible implementations thrown into the React Form Component:
import axios from 'axios';
import { useDataSource } from './useDataSource';
import { useResource } from './useResource';
import { useUser } from './useUser';
const serverResource = resourceUrl => async () => {
const response = await axios.get(resourceUrl);
return response.data;
};
const localStorageResource = key => () => {
return localStorage.getItem(key);
}
export const UserInfo = ({ userId }) => {
// const user = useResource(`/users/${userId}`);
const user = useDataSource(serverResource(`/users/${userId}`));
const message = useDataSource(localStorageResource('message'));
const { name, age, hairColor, hobbies } = user || {};
return user ? (
<>
<h3>{name}</h3>
<p>Age: {age} years</p>
<p>Hair Color: {hairColor}</p>
<h3>Hobbies:</h3>
<ul>
{hobbies.map(hobby => <li key={hobby}>{hobby}</li>)}
</ul>
</>
) : <p>Loading...</p>;
}
And here's the DAO Factory Pattern example provided by Oracle:
src: https://www.oracle.com/java/technologies/dataaccessobject.html
// Abstract class DAO Factory
public abstract class DAOFactory {
// List of DAO types supported by the factory
public static final int CLOUDSCAPE = 1;
public static final int ORACLE = 2;
public static final int SYBASE = 3;
...
// There will be a method for each DAO that can be
// created. The concrete factories will have to
// implement these methods.
public abstract CustomerDAO getCustomerDAO();
public abstract AccountDAO getAccountDAO();
public abstract OrderDAO getOrderDAO();
...
public static DAOFactory getDAOFactory(
int whichFactory) {
switch (whichFactory) {
case CLOUDSCAPE:
return new CloudscapeDAOFactory();
case ORACLE :
return new OracleDAOFactory();
case SYBASE :
return new SybaseDAOFactory();
...
default :
return null;
}
}
}
...with a concrete implementation:
// Cloudscape concrete DAO Factory implementation
import java.sql.*;
public class CloudscapeDAOFactory extends DAOFactory {
public static final String DRIVER=
"COM.cloudscape.core.RmiJdbcDriver";
public static final String DBURL=
"jdbc:cloudscape:rmi://localhost:1099/CoreJ2EEDB";
// method to create Cloudscape connections
public static Connection createConnection() {
// Use DRIVER and DBURL to create a connection
// Recommend connection pool implementation/usage
}
public CustomerDAO getCustomerDAO() {
// CloudscapeCustomerDAO implements CustomerDAO
return new CloudscapeCustomerDAO();
}
public AccountDAO getAccountDAO() {
// CloudscapeAccountDAO implements AccountDAO
return new CloudscapeAccountDAO();
}
public OrderDAO getOrderDAO() {
// CloudscapeOrderDAO implements OrderDAO
return new CloudscapeOrderDAO();
}
...
}
how is the common approach to handle this challenges in React to make the code maintainable?
sure you can. As design patterns do not depend on programming language.
If you are using TypeScript, then you can use Abstract class
If you are using plain JavaScript, then you can use the following approach
An example of using Factory in React can be seen here.
Related
i am trying to configure new data filter for IMayHaveCreator. I saw example for ISoftDelete and did the same thing.
in MyAppEntityFrameworkCoreModule ive added another configure method for Filter but it does not work
public class SimplyAirEntityFrameworkCoreModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
SimplyAirEfCoreEntityExtensionMappings.Configure();
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddAbpDbContext<SimplyAirDbContext>(options =>
{
/* Remove "includeAllEntities: true" to create
* default repositories only for aggregate roots */
options.AddDefaultRepositories(includeAllEntities: true);
});
Configure<AbpDbContextOptions>(options =>
{
/* The main point to change your DBMS.
* See also SimplyAirMigrationsDbContextFactory for EF Core tooling. */
options.UseNpgsql();
});
Configure<AbpDataFilterOptions>(options =>
{
options.DefaultStates[typeof(IMayHaveCreator)] = new DataFilterState(isEnabled: true);
});
}
}
am i doing something wrong
I've managed to implement it. solution was to add override for CreateFilterExpression and ShouldFilterEntity methods in dbContext for that interface
I am new in react-native coding but have experienced on objective-c and swift coding and want use singleton pattern in react-native.
I have tried to find out the solution from other StackOverflow answer but most of them are creating only singleton functions as below code:
var Singleton = (function () {
var instance;
function createInstance() {
var object = new Object("I am the instance");
return object;
}
return {
getInstance: function () {
if (!instance) {
instance = createInstance();
}
return instance;
}
};
})();
function run() {
var instance1 = Singleton.getInstance();
var instance2 = Singleton.getInstance();
alert("Same instance? " + (instance1 === instance2));
}
As we can see in above code here we are creating singleton function not class.
Please let me know if any way to create singleton class and pass multiple variables in that class as objective-c or swift.
Note: Please also notify me if I am going in the wrong direction.
Here's my implementation for singleton class...
Controller.js
export default class Controller {
static instance = Controller.instance || new Controller()
helloWorld() {
console.log("Hello World... \(^_^)/ !!")
}
}
Usage:
import Controller from 'Controller.js'
Controller.instance.helloWorld()
You can use something like that
class SingletonClass {
static instance = null;
static createInstance() {
var object = new SingletonClass();
return object;
}
static getInstance () {
if (!SingletonClass.instance) {
SingletonClass.instance = SingletonClass.createInstance();
}
return SingletonClass.instance;
}
}
var instance1 = SingletonClass.getInstance();
var instance2 = SingletonClass.getInstance();
The singleton pattern isn't used much in the JS ecosystem. What you should look into is http://mobx.js.org. MobX is a library that allows you to create observable objects to store data for your apps. You instantiate one store for each domain you please and make edits to that store to change app state.
I'm trying to move to another database dynamically. I've seen several questions that showed change db files from one to another and they just getting some information from next database. But what I need is completely moving to second database. How should I do this? I've seen that in order to achieve this dsn (in db.php file) should be altered. But I changed it and it's still not changed?? I should have full access to second database closing first one. Give me advice please
Configs like db.php are not intended to be changed in process (while PHP is processing). They are loaded once in the initialization, when request is entered the framework.
As an alternative, you can configure second DB beforehand in db.php, and change between them dynamically like:
Yii::$app->db // your default Database
and
Yii::$app->db2 // Second configured Database, to which you can switch dynamically later
You can learn about multiple database connections here
So, if you want ActiveRecord(for instance User) to be able to access two databases, you can define some static variable, which specifies from which DB to read/write. For example:
class User extends \yii\db\ActiveRecord
{
const DB_DATABASE1 = 'db1';
const DB_DATABASE2 = 'db2';
private static $db = self::DB_DATABASE1;
public static function setDb($db)
{
self::$db = $db;
}
public static function getDb()
{
switch (self::$db) {
case self::DB_DATABASE1:
return Yii::$app->db;
case self::DB_DATABASE2:
return Yii::$app->db2;
default:
throw new \Exception("Database is not selected");
}
}
//...
And then use it in Controller like:
User::setDb(User::DB_DATABASE1);
$usersDB1 = User::find()->all();
User::setDb(User::DB_DATABASE2);
$usersDB2 = User::find()->all();
Set up multiple database connections in your main.php or main-local.php configuration
Yii::$app->db1;
Yii::$app->db2;
Yii::$app->db3;
when making inquiries
$usersDB1=User::find()->all(Yii::$app->db1);
$usersDB2=User::find()->all(Yii::$app->db2);
$usersDB3=User::find()->all(Yii::$app->db3);
Globally switch to a different database dynamically
I have combined Yerke's answer above and Write & use a custom Component in Yii2.0 here.
First, create a component class to do the DB switching. Here, I call it DbSelector and put it in app\components\DbSelector.php.
namespace app\components;
use Yii;
use yii\base\Component;
use yii\base\InvalidConfigException;
class DbSelector extends Component {
const DB_MAIN = 'db';
const DB_SUB1 = 'db1';
const DB_SUB2 = 'db2';
private static $db = self::DB_MAIN;
public static function setDb($db)
{
self::$db = $db;
}
public static function getDb()
{
return \Yii::$app->get(self::$db);
}
}
Second, modify the config/web.php file or whichever your config file is to have multiple databases and add DbSelector as a Yii::$app component.
$config = [
'components' => [
//...
'db' => $db,
'db1' => $db1,
'db2' => $db2,
'dbSelector' => [
'class' => 'app\components\DbSelector',
],
//...
],
//...
];
Third, in each model class, add the following static function getDb() to call the DbSelector getDb():
public static function getDb()
{
return \Yii::$app->dbSelector->getDb();
}
For example,
class DiningTable extends \yii\db\ActiveRecord
{
public static function tableName()
{
return '{{%dining_table}}';
}
public static function getDb()
{
return \Yii::$app->dbSelector->getDb();
}
//...
}
class Customer extends \yii\db\ActiveRecord
{
public static function tableName()
{
return '{{%customer}}';
}
public static function getDb()
{
return \Yii::$app->dbSelector->getDb();
}
//...
}
Lastly, to globally switch to a different database, use \Yii::$app->dbSelector->setDb(YOUR_PREFERRED_DB),
use app\components\DbSelector;
//...
\Yii::$app->dbSelector->setDb(DbSelector::DB_SUB1);
$tables_1 = DiningTable::findAll();
$customers_1 = Customer::find()->where(['<', 'dob', '2000-01-01'])->all();
\Yii::$app->dbSelector->setDb(DbSelector::DB_MAIN);
$tables_main = DiningTable::findAll();
$customers_main = Customer::find()->where(['<', 'dob', '2000-01-01'])->all();
I'm in the process of learning Angular 2 using TypeScript. So far I've written a little API service that uses HTTP get method to feed me json data using observables. Everything is working fine, I can use the data in my view, I can also use the data in my component, but only while I'm subscribed to the getData() method.
Why is that and what other possibilities do I have to make the object array available to all methods in my component for easy iteration and management?
Example component:
export class SomeComponent implements OnInit {
public someData: DataObject[];
public constructor(private service: SomeService) {}
public ngOnInit(): void {
this.loadData();
this.useData();
}
private loadData(): void {
this.service.getData().subscribe(data=> {
this.someData = data;
this.someData.forEach(dataObject => {
// this works fine
});
});
}
private useData(): void {
this.someData.forEach(dataObject => {
// dataObject is (of type?) undefined, why?
});
}
}
It's because http calls are async. Your this.useData(); does not wait this.loadData(); to finish. This should work:
private loadData(): void {
this.service.getData().subscribe(data=> {
this.someData = data;
this.useData();
});
}
I'm trying to test that the model returned from my Nancy application is as expected. I have followed the docs here but whenever I call the GetModel<T> extension method it throws a KeyNotFoundException.
System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
I know what the error means but I'm failing to see why it's being thrown.
Here's my module
public class SanityModule : NancyModule
{
public SanityModule()
{
Get["sanity-check"] = _ => Negotiate.WithModel(new SanityViewModel { Id = 1 })
.WithStatusCode(HttpStatusCode.OK);
}
}
my view model
public class SanityViewModel
{
public int Id { get; set; }
}
and here's my test
[TestFixture]
public class SanityModuleTests
{
[Test]
public void Sanity_Check()
{
// Arrange
var browser = new Browser(with =>
{
with.Module<SanityModule>();
with.ViewFactory<TestingViewFactory>();
});
// Act
var result = browser.Get("/sanity-check", with =>
{
with.HttpRequest();
with.Header("accept", "application/json");
});
var model = result.GetModel<SanityViewModel>();
// Asset
model.Id.ShouldBeEquivalentTo(1);
}
}
Debugging this test shows that the module is hit and completes just fine. Running the application shows that the response is as expected.
Can anyone shed some light on this?
Thanks to the lovely guys, albertjan and the.fringe.ninja, in the Nancy Jabbr room we've got an explanation as to what's going on here.
TL;DR It makes sense for this to not work but the error message should be more descriptive. There is a workaround below.
The issue here is that I am requesting the response as application/json whilst using TestingViewFactory.
Let's take a look at the implementation of GetModel<T>();
public static TType GetModel<TType>(this BrowserResponse response)
{
return (TType)response.Context.Items[TestingViewContextKeys.VIEWMODEL];
}
This is simply grabbing the view model from the NancyContext and casting it to your type. This is where the error is thrown, as there is no view model in NancyContext. This is because the view model is added to NancyContext in the RenderView method of TestingViewFactory.
public Response RenderView(string viewName, dynamic model, ViewLocationContext viewLocationContext)
{
// Intercept and store interesting stuff
viewLocationContext.Context.Items[TestingViewContextKeys.VIEWMODEL] = model;
viewLocationContext.Context.Items[TestingViewContextKeys.VIEWNAME] = viewName;
viewLocationContext.Context.Items[TestingViewContextKeys.MODULENAME] = viewLocationContext.ModuleName;
viewLocationContext.Context.Items[TestingViewContextKeys.MODULEPATH] = viewLocationContext.ModulePath;
return this.decoratedViewFactory.RenderView(viewName, model, viewLocationContext);
}
My test is requesting json so RenderView will not be called. This means you can only use GetModel<T> if you use a html request.
Workaround
My application is an api so I do not have any views so changing the line
with.Header("accept", "application/json");
to
with.Header("accept", "text/html");
will throw a ViewNotFoundException. To avoid this I need to implement my own IViewFactory. (this comes from the.fringe.ninja)
public class TestViewFactory : IViewFactory
{
#region IViewFactory Members
public Nancy.Response RenderView(string viewName, dynamic model, ViewLocationContext viewLocationContext)
{
viewLocationContext.Context.Items[Fixtures.SystemUnderTest.ViewModelKey] = model;
return new HtmlResponse();
}
#endregion
}
Then it is simply a case of updating
with.ViewFactory<TestingViewFactory>();
to
with.ViewFactory<TestViewFactory>();
Now GetModel<T> should work without needing a view.